aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2011-07-17 15:40:56 +0000
committerDimitry Andric <dim@FreeBSD.org>2011-07-17 15:40:56 +0000
commit180abc3db9ae3b4fc63cd65b15697e6ffcc8a657 (patch)
tree2097d084eb235c0b12c0bff3445f4ec7bbaa8a12
parent29cafa66ad3878dbb9f82615f19fa0bded2e443c (diff)
downloadsrc-180abc3db9ae3b4fc63cd65b15697e6ffcc8a657.tar.gz
src-180abc3db9ae3b4fc63cd65b15697e6ffcc8a657.zip
Vendor import of clang trunk r135360:vendor/clang/clang-r135360
Notes
Notes: svn path=/vendor/clang/dist/; revision=224135 svn path=/vendor/clang/clang-r135360/; revision=224136; tag=vendor/clang/clang-r135360
-rw-r--r--CMakeLists.txt13
-rw-r--r--INPUTS/cfg-big-switch.c27
-rw-r--r--INPUTS/cfg-long-chain1.c20
-rw-r--r--INPUTS/cfg-long-chain2.c20
-rw-r--r--INPUTS/cfg-long-chain3.c21
-rw-r--r--INPUTS/cfg-nested-switches.c36
-rw-r--r--LICENSE.TXT2
-rw-r--r--bindings/python/clang/cindex.py22
-rw-r--r--bindings/python/tests/cindex/test_cursor_kind.py8
-rw-r--r--bindings/python/tests/cindex/test_translation_unit.py15
-rw-r--r--clang.xcodeproj/project.pbxproj43
-rw-r--r--docs/AutomaticReferenceCounting.html1857
-rw-r--r--docs/Block-ABI-Apple.txt4
-rw-r--r--docs/BlockLanguageSpec.txt2
-rw-r--r--docs/DriverInternals.html2
-rw-r--r--docs/InternalsManual.html9
-rw-r--r--docs/LanguageExtensions.html119
-rw-r--r--docs/UsersManual.html18
-rw-r--r--docs/index.html4
-rw-r--r--include/clang-c/Index.h255
-rw-r--r--include/clang/ARCMigrate/ARCMT.h94
-rw-r--r--include/clang/ARCMigrate/ARCMTActions.h47
-rw-r--r--include/clang/ARCMigrate/FileRemapper.h76
-rw-r--r--include/clang/AST/ASTContext.h40
-rw-r--r--include/clang/AST/ASTDiagnostic.h22
-rw-r--r--include/clang/AST/CanonicalType.h2
-rw-r--r--include/clang/AST/Decl.h34
-rw-r--r--include/clang/AST/DeclBase.h19
-rw-r--r--include/clang/AST/DeclCXX.h1
-rw-r--r--include/clang/AST/DeclObjC.h43
-rw-r--r--include/clang/AST/DeclTemplate.h8
-rw-r--r--include/clang/AST/DeclarationName.h3
-rw-r--r--include/clang/AST/Expr.h211
-rw-r--r--include/clang/AST/ExprCXX.h170
-rw-r--r--include/clang/AST/ExprObjC.h149
-rw-r--r--include/clang/AST/ExternalASTSource.h24
-rw-r--r--include/clang/AST/GlobalDecl.h (renamed from lib/CodeGen/GlobalDecl.h)25
-rw-r--r--include/clang/AST/NestedNameSpecifier.h12
-rw-r--r--include/clang/AST/OperationKinds.h30
-rw-r--r--include/clang/AST/ParentMap.h1
-rw-r--r--include/clang/AST/PrettyPrinter.h6
-rw-r--r--include/clang/AST/RecursiveASTVisitor.h7
-rw-r--r--include/clang/AST/Stmt.h29
-rw-r--r--include/clang/AST/StmtObjC.h33
-rw-r--r--include/clang/AST/TemplateBase.h7
-rw-r--r--include/clang/AST/TemplateName.h110
-rw-r--r--include/clang/AST/Type.h420
-rw-r--r--include/clang/Analysis/Analyses/UninitializedValues.h10
-rw-r--r--include/clang/Analysis/AnalysisContext.h5
-rw-r--r--include/clang/Analysis/DomainSpecific/CocoaConventions.h25
-rw-r--r--include/clang/Basic/Attr.td9
-rw-r--r--include/clang/Basic/Builtins.def6
-rw-r--r--include/clang/Basic/Builtins.h1
-rw-r--r--include/clang/Basic/BuiltinsX86.def82
-rw-r--r--include/clang/Basic/DelayedCleanupPool.h109
-rw-r--r--include/clang/Basic/Diagnostic.h53
-rw-r--r--include/clang/Basic/DiagnosticCategories.h26
-rw-r--r--include/clang/Basic/DiagnosticCommonKinds.td1
-rw-r--r--include/clang/Basic/DiagnosticDriverKinds.td6
-rw-r--r--include/clang/Basic/DiagnosticFrontendKinds.td3
-rw-r--r--include/clang/Basic/DiagnosticGroups.td22
-rw-r--r--include/clang/Basic/DiagnosticIDs.h4
-rw-r--r--include/clang/Basic/DiagnosticLexKinds.td2
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.td5
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td338
-rw-r--r--include/clang/Basic/FileManager.h5
-rw-r--r--include/clang/Basic/IdentifierTable.h20
-rw-r--r--include/clang/Basic/LangOptions.h13
-rw-r--r--include/clang/Basic/SourceManager.h144
-rw-r--r--include/clang/Basic/SourceManagerInternals.h2
-rw-r--r--include/clang/Basic/Specifiers.h2
-rw-r--r--include/clang/Basic/StmtNodes.td7
-rw-r--r--include/clang/Basic/TargetInfo.h24
-rw-r--r--include/clang/Basic/TokenKinds.def7
-rw-r--r--include/clang/Basic/arm_neon.td4
-rw-r--r--include/clang/CodeGen/BackendUtil.h4
-rw-r--r--include/clang/Driver/CC1Options.td40
-rw-r--r--include/clang/Driver/Compilation.h1
-rw-r--r--include/clang/Driver/Driver.h2
-rw-r--r--include/clang/Driver/ObjCRuntime.h46
-rw-r--r--include/clang/Driver/Option.h7
-rw-r--r--include/clang/Driver/Options.td20
-rw-r--r--include/clang/Driver/ToolChain.h10
-rw-r--r--include/clang/Frontend/ASTUnit.h14
-rw-r--r--include/clang/Frontend/CodeGenOptions.h13
-rw-r--r--include/clang/Frontend/DependencyOutputOptions.h2
-rw-r--r--include/clang/Frontend/DiagnosticOptions.h3
-rw-r--r--include/clang/Frontend/FrontendAction.h39
-rw-r--r--include/clang/Frontend/FrontendActions.h6
-rw-r--r--include/clang/Frontend/FrontendOptions.h11
-rw-r--r--include/clang/Frontend/HeaderSearchOptions.h27
-rw-r--r--include/clang/Frontend/PreprocessorOptions.h27
-rw-r--r--include/clang/Frontend/TextDiagnosticPrinter.h19
-rw-r--r--include/clang/Frontend/Utils.h1
-rw-r--r--include/clang/Lex/Lexer.h22
-rw-r--r--include/clang/Lex/LiteralSupport.h4
-rw-r--r--include/clang/Lex/MacroInfo.h16
-rw-r--r--include/clang/Lex/PPCallbacks.h37
-rw-r--r--include/clang/Lex/PreprocessingRecord.h34
-rw-r--r--include/clang/Lex/Preprocessor.h55
-rw-r--r--include/clang/Lex/Token.h4
-rw-r--r--include/clang/Lex/TokenLexer.h33
-rw-r--r--include/clang/Parse/Parser.h72
-rw-r--r--include/clang/Rewrite/FixItRewriter.h1
-rw-r--r--include/clang/Rewrite/Rewriter.h5
-rw-r--r--include/clang/Sema/AnalysisBasedWarnings.h38
-rw-r--r--include/clang/Sema/AttributeList.h48
-rw-r--r--include/clang/Sema/CodeCompleteConsumer.h30
-rw-r--r--include/clang/Sema/DeclSpec.h59
-rw-r--r--include/clang/Sema/DelayedDiagnostic.h41
-rw-r--r--include/clang/Sema/ExternalSemaSource.h5
-rw-r--r--include/clang/Sema/Initialization.h107
-rw-r--r--include/clang/Sema/LocInfoType.h63
-rw-r--r--include/clang/Sema/Overload.h18
-rw-r--r--include/clang/Sema/Scope.h8
-rw-r--r--include/clang/Sema/Sema.h332
-rw-r--r--include/clang/Sema/TypoCorrection.h105
-rw-r--r--include/clang/Serialization/ASTBitCodes.h40
-rw-r--r--include/clang/Serialization/ASTReader.h10
-rw-r--r--include/clang/Serialization/ASTWriter.h2
-rw-r--r--include/clang/Serialization/ChainedIncludesSource.h2
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h4
-rw-r--r--lib/ARCMigrate/ARCMT.cpp541
-rw-r--r--lib/ARCMigrate/ARCMTActions.cpp53
-rw-r--r--lib/ARCMigrate/CMakeLists.txt24
-rw-r--r--lib/ARCMigrate/FileRemapper.cpp291
-rw-r--r--lib/ARCMigrate/Internals.h148
-rw-r--r--lib/ARCMigrate/Makefile18
-rw-r--r--lib/ARCMigrate/TransARCAssign.cpp75
-rw-r--r--lib/ARCMigrate/TransAutoreleasePool.cpp436
-rw-r--r--lib/ARCMigrate/TransBlockObjCVariable.cpp143
-rw-r--r--lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp211
-rw-r--r--lib/ARCMigrate/TransProperties.cpp364
-rw-r--r--lib/ARCMigrate/TransRetainReleaseDealloc.cpp219
-rw-r--r--lib/ARCMigrate/TransUnbridgedCasts.cpp203
-rw-r--r--lib/ARCMigrate/TransUnusedInitDelegate.cpp74
-rw-r--r--lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp198
-rw-r--r--lib/ARCMigrate/TransformActions.cpp699
-rw-r--r--lib/ARCMigrate/Transforms.cpp296
-rw-r--r--lib/ARCMigrate/Transforms.h92
-rw-r--r--lib/AST/ASTContext.cpp293
-rw-r--r--lib/AST/ASTDiagnostic.cpp74
-rw-r--r--lib/AST/ASTImporter.cpp20
-rw-r--r--lib/AST/Decl.cpp110
-rw-r--r--lib/AST/DeclBase.cpp35
-rw-r--r--lib/AST/DeclCXX.cpp54
-rw-r--r--lib/AST/DeclObjC.cpp58
-rw-r--r--lib/AST/DeclPrinter.cpp5
-rw-r--r--lib/AST/DeclarationName.cpp22
-rw-r--r--lib/AST/Expr.cpp256
-rw-r--r--lib/AST/ExprCXX.cpp60
-rw-r--r--lib/AST/ExprClassification.cpp15
-rw-r--r--lib/AST/ExprConstant.cpp68
-rw-r--r--lib/AST/ExternalASTSource.cpp4
-rw-r--r--lib/AST/ItaniumMangle.cpp447
-rw-r--r--lib/AST/NestedNameSpecifier.cpp22
-rw-r--r--lib/AST/ParentMap.cpp9
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp9
-rw-r--r--lib/AST/Stmt.cpp33
-rw-r--r--lib/AST/StmtPrinter.cpp26
-rw-r--r--lib/AST/StmtProfile.cpp308
-rw-r--r--lib/AST/TemplateBase.cpp43
-rw-r--r--lib/AST/TemplateName.cpp40
-rw-r--r--lib/AST/Type.cpp547
-rw-r--r--lib/AST/TypePrinter.cpp117
-rw-r--r--lib/Analysis/CFG.cpp6
-rw-r--r--lib/Analysis/CocoaConventions.cpp65
-rw-r--r--lib/Analysis/FormatString.cpp3
-rw-r--r--lib/Analysis/ReachableCode.cpp6
-rw-r--r--lib/Analysis/UninitializedValues.cpp46
-rw-r--r--lib/Basic/Builtins.cpp22
-rw-r--r--lib/Basic/Diagnostic.cpp16
-rw-r--r--lib/Basic/DiagnosticIDs.cpp81
-rw-r--r--lib/Basic/IdentifierTable.cpp9
-rw-r--r--lib/Basic/SourceManager.cpp121
-rw-r--r--lib/Basic/TargetInfo.cpp39
-rw-r--r--lib/Basic/Targets.cpp348
-rw-r--r--lib/CMakeLists.txt1
-rw-r--r--lib/CodeGen/ABIInfo.h12
-rw-r--r--lib/CodeGen/BackendUtil.cpp46
-rw-r--r--lib/CodeGen/CGBlocks.cpp316
-rw-r--r--lib/CodeGen/CGBlocks.h3
-rw-r--r--lib/CodeGen/CGBuiltin.cpp348
-rw-r--r--lib/CodeGen/CGCXXABI.cpp2
-rw-r--r--lib/CodeGen/CGCXXABI.h2
-rw-r--r--lib/CodeGen/CGCall.cpp555
-rw-r--r--lib/CodeGen/CGCall.h47
-rw-r--r--lib/CodeGen/CGClass.cpp390
-rw-r--r--lib/CodeGen/CGCleanup.cpp35
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp51
-rw-r--r--lib/CodeGen/CGDebugInfo.h8
-rw-r--r--lib/CodeGen/CGDecl.cpp770
-rw-r--r--lib/CodeGen/CGDeclCXX.cpp162
-rw-r--r--lib/CodeGen/CGException.cpp212
-rw-r--r--lib/CodeGen/CGExpr.cpp450
-rw-r--r--lib/CodeGen/CGExprAgg.cpp319
-rw-r--r--lib/CodeGen/CGExprCXX.cpp147
-rw-r--r--lib/CodeGen/CGExprComplex.cpp93
-rw-r--r--lib/CodeGen/CGExprConstant.cpp42
-rw-r--r--lib/CodeGen/CGExprScalar.cpp494
-rw-r--r--lib/CodeGen/CGObjC.cpp1255
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp224
-rw-r--r--lib/CodeGen/CGObjCMac.cpp791
-rw-r--r--lib/CodeGen/CGObjCRuntime.cpp28
-rw-r--r--lib/CodeGen/CGObjCRuntime.h8
-rw-r--r--lib/CodeGen/CGRTTI.cpp4
-rw-r--r--lib/CodeGen/CGRecordLayout.h16
-rw-r--r--lib/CodeGen/CGRecordLayoutBuilder.cpp69
-rw-r--r--lib/CodeGen/CGStmt.cpp32
-rw-r--r--lib/CodeGen/CGTemporaries.cpp9
-rw-r--r--lib/CodeGen/CGVTT.cpp3
-rw-r--r--lib/CodeGen/CGVTables.cpp5
-rw-r--r--lib/CodeGen/CGVTables.h2
-rw-r--r--lib/CodeGen/CGValue.h81
-rw-r--r--lib/CodeGen/CodeGenAction.cpp12
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp262
-rw-r--r--lib/CodeGen/CodeGenFunction.h414
-rw-r--r--lib/CodeGen/CodeGenModule.cpp58
-rw-r--r--lib/CodeGen/CodeGenModule.h125
-rw-r--r--lib/CodeGen/CodeGenTypes.cpp617
-rw-r--r--lib/CodeGen/CodeGenTypes.h130
-rw-r--r--lib/CodeGen/ItaniumCXXABI.cpp123
-rw-r--r--lib/CodeGen/TargetInfo.cpp274
-rw-r--r--lib/CodeGen/TargetInfo.h20
-rw-r--r--lib/Driver/Arg.cpp2
-rw-r--r--lib/Driver/ArgList.cpp4
-rw-r--r--lib/Driver/Driver.cpp41
-rw-r--r--lib/Driver/Option.cpp16
-rw-r--r--lib/Driver/ToolChain.cpp34
-rw-r--r--lib/Driver/ToolChains.cpp161
-rw-r--r--lib/Driver/ToolChains.h26
-rw-r--r--lib/Driver/Tools.cpp267
-rw-r--r--lib/Driver/Tools.h2
-rw-r--r--lib/Frontend/ASTUnit.cpp85
-rw-r--r--lib/Frontend/BoostConAction.cpp39
-rw-r--r--lib/Frontend/CMakeLists.txt1
-rw-r--r--lib/Frontend/CacheTokens.cpp7
-rw-r--r--lib/Frontend/CompilerInstance.cpp3
-rw-r--r--lib/Frontend/CompilerInvocation.cpp123
-rw-r--r--lib/Frontend/DependencyFile.cpp55
-rw-r--r--lib/Frontend/FrontendAction.cpp46
-rw-r--r--lib/Frontend/InitHeaderSearch.cpp217
-rw-r--r--lib/Frontend/InitPreprocessor.cpp170
-rw-r--r--lib/Frontend/PrintPreprocessedOutput.cpp48
-rw-r--r--lib/Frontend/TextDiagnosticPrinter.cpp115
-rw-r--r--lib/FrontendTool/CMakeLists.txt3
-rw-r--r--lib/FrontendTool/ExecuteCompilerInvocation.cpp17
-rw-r--r--lib/Headers/float.h42
-rw-r--r--lib/Headers/stdarg.h2
-rw-r--r--lib/Lex/HeaderSearch.cpp6
-rw-r--r--lib/Lex/Lexer.cpp84
-rw-r--r--lib/Lex/MacroArgs.cpp11
-rw-r--r--lib/Lex/MacroArgs.h7
-rw-r--r--lib/Lex/MacroInfo.cpp32
-rw-r--r--lib/Lex/PPDirectives.cpp22
-rw-r--r--lib/Lex/PPLexerChange.cpp4
-rw-r--r--lib/Lex/PPMacroExpansion.cpp72
-rw-r--r--lib/Lex/Pragma.cpp30
-rw-r--r--lib/Lex/PreprocessingRecord.cpp11
-rw-r--r--lib/Lex/Preprocessor.cpp18
-rw-r--r--lib/Lex/TokenLexer.cpp182
-rwxr-xr-xlib/Makefile4
-rw-r--r--lib/Parse/ParseAST.cpp9
-rw-r--r--lib/Parse/ParseDecl.cpp498
-rw-r--r--lib/Parse/ParseDeclCXX.cpp37
-rw-r--r--lib/Parse/ParseExpr.cpp156
-rw-r--r--lib/Parse/ParseExprCXX.cpp49
-rw-r--r--lib/Parse/ParseObjc.cpp46
-rw-r--r--lib/Parse/ParseStmt.cpp23
-rw-r--r--lib/Parse/ParseTemplate.cpp4
-rw-r--r--lib/Parse/ParseTentative.cpp3
-rw-r--r--lib/Parse/Parser.cpp26
-rw-r--r--lib/Rewrite/FixItRewriter.cpp3
-rw-r--r--lib/Rewrite/HTMLRewrite.cpp2
-rw-r--r--lib/Rewrite/RewriteObjC.cpp20
-rw-r--r--lib/Rewrite/Rewriter.cpp73
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp84
-rw-r--r--lib/Sema/AttributeList.cpp6
-rw-r--r--lib/Sema/CMakeLists.txt1
-rw-r--r--lib/Sema/CodeCompleteConsumer.cpp8
-rw-r--r--lib/Sema/DeclSpec.cpp80
-rw-r--r--lib/Sema/DelayedDiagnostic.cpp3
-rw-r--r--lib/Sema/JumpDiagnostics.cpp224
-rw-r--r--lib/Sema/Sema.cpp59
-rw-r--r--lib/Sema/SemaCXXCast.cpp162
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp58
-rw-r--r--lib/Sema/SemaChecking.cpp541
-rw-r--r--lib/Sema/SemaCodeComplete.cpp154
-rw-r--r--lib/Sema/SemaDecl.cpp444
-rw-r--r--lib/Sema/SemaDeclAttr.cpp1115
-rw-r--r--lib/Sema/SemaDeclCXX.cpp575
-rw-r--r--lib/Sema/SemaDeclObjC.cpp540
-rw-r--r--lib/Sema/SemaExpr.cpp2769
-rw-r--r--lib/Sema/SemaExprCXX.cpp439
-rw-r--r--lib/Sema/SemaExprMember.cpp1594
-rw-r--r--lib/Sema/SemaExprObjC.cpp627
-rw-r--r--lib/Sema/SemaInit.cpp410
-rw-r--r--lib/Sema/SemaLookup.cpp990
-rw-r--r--lib/Sema/SemaObjCProperty.cpp432
-rw-r--r--lib/Sema/SemaOverload.cpp367
-rw-r--r--lib/Sema/SemaStmt.cpp77
-rw-r--r--lib/Sema/SemaTemplate.cpp134
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp328
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp151
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp42
-rw-r--r--lib/Sema/SemaTemplateVariadic.cpp16
-rw-r--r--lib/Sema/SemaType.cpp848
-rw-r--r--lib/Sema/TreeTransform.h175
-rw-r--r--lib/Sema/TypeLocBuilder.h27
-rw-r--r--lib/Serialization/ASTReader.cpp77
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp1
-rw-r--r--lib/Serialization/ASTReaderStmt.cpp263
-rw-r--r--lib/Serialization/ASTWriter.cpp63
-rw-r--r--lib/Serialization/ASTWriterDecl.cpp22
-rw-r--r--lib/Serialization/ASTWriterStmt.cpp228
-rw-r--r--lib/Serialization/ChainedIncludesSource.cpp3
-rw-r--r--lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/CStringChecker.cpp756
-rw-r--r--lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/Checkers.td8
-rw-r--r--lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp6
-rw-r--r--lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp27
-rw-r--r--lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp79
-rw-r--r--lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp20
-rw-r--r--lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp110
-rw-r--r--lib/StaticAnalyzer/Core/CFRefCount.cpp142
-rw-r--r--lib/StaticAnalyzer/Core/Environment.cpp3
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngine.cpp78
-rw-r--r--lib/StaticAnalyzer/Core/RegionStore.cpp7
-rw-r--r--lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp36
-rw-r--r--runtime/compiler-rt/Makefile2
-rw-r--r--test/ARCMT/Common.h55
-rw-r--r--test/ARCMT/Inputs/test.h15
-rw-r--r--test/ARCMT/Inputs/test.h.result13
-rw-r--r--test/ARCMT/Inputs/test1.m.in6
-rw-r--r--test/ARCMT/Inputs/test1.m.in.result5
-rw-r--r--test/ARCMT/Inputs/test2.m.in6
-rw-r--r--test/ARCMT/Inputs/test2.m.in.result5
-rw-r--r--test/ARCMT/assign-prop-no-arc-runtime.m15
-rw-r--r--test/ARCMT/assign-prop-no-arc-runtime.m.result15
-rw-r--r--test/ARCMT/assign-prop-with-arc-runtime.m40
-rw-r--r--test/ARCMT/assign-prop-with-arc-runtime.m.result40
-rw-r--r--test/ARCMT/atautorelease-2.m29
-rw-r--r--test/ARCMT/atautorelease-2.m.result28
-rw-r--r--test/ARCMT/atautorelease-3.m40
-rw-r--r--test/ARCMT/atautorelease-3.m.result31
-rw-r--r--test/ARCMT/atautorelease-check.m144
-rw-r--r--test/ARCMT/atautorelease.m47
-rw-r--r--test/ARCMT/atautorelease.m.result46
-rw-r--r--test/ARCMT/autoreleases.m48
-rw-r--r--test/ARCMT/autoreleases.m.result48
-rw-r--r--test/ARCMT/checking.m295
-rw-r--r--test/ARCMT/cxx-checking.mm105
-rw-r--r--test/ARCMT/cxx-rewrite.mm31
-rw-r--r--test/ARCMT/cxx-rewrite.mm.result31
-rw-r--r--test/ARCMT/dealloc.m24
-rw-r--r--test/ARCMT/dealloc.m.result20
-rw-r--r--test/ARCMT/driver-migrate.m3
-rw-r--r--test/ARCMT/init.m37
-rw-r--r--test/ARCMT/init.m.result37
-rw-r--r--test/ARCMT/migrate.m4
-rw-r--r--test/ARCMT/nonobjc-to-objc-cast-2.m14
-rw-r--r--test/ARCMT/nonobjc-to-objc-cast.m38
-rw-r--r--test/ARCMT/nonobjc-to-objc-cast.m.result38
-rw-r--r--test/ARCMT/releases-driver.m68
-rw-r--r--test/ARCMT/releases-driver.m.result61
-rw-r--r--test/ARCMT/releases.m87
-rw-r--r--test/ARCMT/releases.m.result79
-rw-r--r--test/ARCMT/remove-dealloc-method.m26
-rw-r--r--test/ARCMT/remove-dealloc-method.m.result20
-rw-r--r--test/ARCMT/remove-dealloc-zerouts.m44
-rw-r--r--test/ARCMT/remove-dealloc-zerouts.m.result39
-rw-r--r--test/ARCMT/remove-statements.m45
-rw-r--r--test/ARCMT/remove-statements.m.result38
-rw-r--r--test/ARCMT/retains.m71
-rw-r--r--test/ARCMT/retains.m.result65
-rw-r--r--test/ARCMT/rewrite-block-var.m25
-rw-r--r--test/ARCMT/rewrite-block-var.m.result25
-rw-r--r--test/ARCMT/safe-arc-assign.m14
-rw-r--r--test/ARCMT/safe-arc-assign.m.result14
-rw-r--r--test/ARCMT/with-arc-mode-check.m9
-rw-r--r--test/ARCMT/with-arc-mode-migrate.m12
-rw-r--r--test/ARCMT/with-arc-mode-migrate.m.result11
-rw-r--r--test/ARCMT/with-arc-mode-modify.m13
-rw-r--r--test/ARCMT/with-arc-mode-modify.m.result12
-rw-r--r--test/Analysis/bstring.c36
-rw-r--r--test/Analysis/misc-ps-eager-assume.m1
-rw-r--r--test/Analysis/nullptr.cpp8
-rw-r--r--test/Analysis/objc-arc.m149
-rw-r--r--test/Analysis/pr4209.m6
-rw-r--r--test/Analysis/retain-release-gc-only.m1
-rw-r--r--test/Analysis/retain-release-path-notes-gc.m74
-rw-r--r--test/Analysis/retain-release-path-notes.m123
-rw-r--r--test/Analysis/retain-release.m87
-rw-r--r--test/Analysis/retain-release.mm1
-rw-r--r--test/Analysis/string-fail.c113
-rw-r--r--test/Analysis/string.c402
-rw-r--r--test/Analysis/uninit-ps-rdar6145427.m5
-rw-r--r--test/Analysis/uninit-vals-ps-region.m9
-rw-r--r--test/Analysis/uninit-vals.m9
-rw-r--r--test/Analysis/variadic-method-types.m8
-rw-r--r--test/CMakeLists.txt6
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp13
-rw-r--r--test/CXX/class/p6-0x.cpp15
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.stc/p1.cpp4
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp2
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp3
-rw-r--r--test/CXX/except/except.spec/canonical.cpp53
-rw-r--r--test/CXX/except/except.spec/p14-ir.cpp13
-rw-r--r--test/CXX/special/class.copy/p33-0x.cpp32
-rw-r--r--test/CXX/stmt.stmt/stmt.dcl/p3-0x.cpp8
-rw-r--r--test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp2
-rw-r--r--test/CXX/temp/p3.cpp20
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp25
-rw-r--r--test/CXX/temp/temp.res/temp.local/p3.cpp8
-rw-r--r--test/CXX/temp/temp.spec/temp.explicit/p7.cpp4
-rw-r--r--test/CodeGen/annotate.c2
-rw-r--r--test/CodeGen/arm-arguments.c4
-rw-r--r--test/CodeGen/arm-asm-variable.c31
-rw-r--r--test/CodeGen/asm-errors.c6
-rw-r--r--test/CodeGen/asm-inout.c3
-rw-r--r--test/CodeGen/asm.c26
-rw-r--r--test/CodeGen/attr-weak-import.c26
-rw-r--r--test/CodeGen/attributes.c2
-rw-r--r--test/CodeGen/bitfield-2.c8
-rw-r--r--test/CodeGen/blocksignature.c6
-rw-r--r--test/CodeGen/blockstret.c2
-rw-r--r--test/CodeGen/builtin-expect.c26
-rw-r--r--test/CodeGen/byval-memcpy-elim.c33
-rw-r--r--test/CodeGen/call-knr-indirect.c11
-rw-r--r--test/CodeGen/call.c39
-rw-r--r--test/CodeGen/complex-indirect.c10
-rw-r--r--test/CodeGen/complex.c4
-rw-r--r--test/CodeGen/compound-literal.c25
-rw-r--r--test/CodeGen/const-init.c20
-rw-r--r--test/CodeGen/darwin-thread-specifier.c3
-rw-r--r--test/CodeGen/debug-info-iv.c35
-rw-r--r--test/CodeGen/debug-info-member.c3
-rw-r--r--test/CodeGen/debug-info.c5
-rw-r--r--test/CodeGen/decl.c4
-rw-r--r--test/CodeGen/designated-initializers.c10
-rw-r--r--test/CodeGen/flexible-array-init.c4
-rw-r--r--test/CodeGen/functions.c6
-rw-r--r--test/CodeGen/global-init.c4
-rw-r--r--test/CodeGen/init.c8
-rw-r--r--test/CodeGen/libcalls.c23
-rw-r--r--test/CodeGen/mmx-inline-asm.c2
-rw-r--r--test/CodeGen/ms-anonymous-struct.c4
-rw-r--r--test/CodeGen/packed-union.c1
-rw-r--r--test/CodeGen/pragma-pack-3.c2
-rw-r--r--test/CodeGen/private-extern-redef.c39
-rw-r--r--test/CodeGen/struct-init.c10
-rw-r--r--test/CodeGen/struct.c13
-rw-r--r--test/CodeGen/trapv.c20
-rw-r--r--test/CodeGen/union-init2.c4
-rw-r--r--test/CodeGen/vla.c63
-rw-r--r--test/CodeGen/volatile-1.c2
-rw-r--r--test/CodeGen/volatile-2.c12
-rw-r--r--test/CodeGen/x86_32-arguments-darwin.c7
-rw-r--r--test/CodeGen/x86_32-arguments-linux.c2
-rw-r--r--test/CodeGen/x86_32-arguments-nommx.c11
-rw-r--r--test/CodeGen/x86_64-arguments.c55
-rw-r--r--test/CodeGenCXX/anonymous-union-member-initializer.cpp18
-rw-r--r--test/CodeGenCXX/attr-used.cpp4
-rw-r--r--test/CodeGenCXX/block-byref-cxx-objc.cpp4
-rw-r--r--test/CodeGenCXX/blocks.cpp4
-rw-r--r--test/CodeGenCXX/class-layout.cpp2
-rw-r--r--test/CodeGenCXX/compound-literals.cpp27
-rw-r--r--test/CodeGenCXX/const-init.cpp4
-rw-r--r--test/CodeGenCXX/constructor-init.cpp16
-rw-r--r--test/CodeGenCXX/constructors.cpp15
-rw-r--r--test/CodeGenCXX/copy-constructor-elim-2.cpp14
-rw-r--r--test/CodeGenCXX/copy-constructor-synthesis-2.cpp2
-rw-r--r--test/CodeGenCXX/copy-initialization.cpp2
-rw-r--r--test/CodeGenCXX/cxx0x-defaulted-templates.cpp12
-rw-r--r--test/CodeGenCXX/cxx0x-delegating-ctors.cpp20
-rw-r--r--test/CodeGenCXX/default-constructor-default-argument.cpp2
-rw-r--r--test/CodeGenCXX/default-constructor-template-member.cpp6
-rw-r--r--test/CodeGenCXX/delete.cpp58
-rw-r--r--test/CodeGenCXX/destructors.cpp46
-rw-r--r--test/CodeGenCXX/eh.cpp14
-rw-r--r--test/CodeGenCXX/elide-call-reference.cpp4
-rw-r--r--test/CodeGenCXX/for-range.cpp8
-rw-r--r--test/CodeGenCXX/global-init.cpp31
-rw-r--r--test/CodeGenCXX/implicit-copy-constructor.cpp10
-rw-r--r--test/CodeGenCXX/init-incomplete-type.cpp19
-rw-r--r--test/CodeGenCXX/mangle-subst-std.cpp4
-rw-r--r--test/CodeGenCXX/mangle-template.cpp4
-rw-r--r--test/CodeGenCXX/mangle.cpp157
-rw-r--r--test/CodeGenCXX/member-function-pointers.cpp44
-rw-r--r--test/CodeGenCXX/member-init-assignment.cpp4
-rw-r--r--test/CodeGenCXX/member-init-ctor.cpp2
-rw-r--r--test/CodeGenCXX/new-overflow.cpp209
-rw-r--r--test/CodeGenCXX/new.cpp36
-rw-r--r--test/CodeGenCXX/noinline-template.cpp16
-rw-r--r--test/CodeGenCXX/nrvo.cpp42
-rw-r--r--test/CodeGenCXX/partial-destruction.cpp169
-rw-r--r--test/CodeGenCXX/pointers-to-data-members.cpp6
-rw-r--r--test/CodeGenCXX/pr9965.cpp6
-rw-r--r--test/CodeGenCXX/references.cpp32
-rw-r--r--test/CodeGenCXX/static-init-3.cpp4
-rw-r--r--test/CodeGenCXX/static-init.cpp3
-rw-r--r--test/CodeGenCXX/stmtexpr.cpp10
-rw-r--r--test/CodeGenCXX/template-anonymous-types.cpp4
-rw-r--r--test/CodeGenCXX/temporaries.cpp22
-rw-r--r--test/CodeGenCXX/value-init.cpp69
-rw-r--r--test/CodeGenCXX/variadic-templates.cpp11
-rw-r--r--test/CodeGenCXX/virt-call-offsets.cpp2
-rw-r--r--test/CodeGenCXX/virtual-base-destructor-call.cpp30
-rw-r--r--test/CodeGenCXX/virtual-bases.cpp4
-rw-r--r--test/CodeGenCXX/virtual-functions-incomplete-types.cpp2
-rw-r--r--test/CodeGenCXX/virtual-pseudo-destructor-call.cpp6
-rw-r--r--test/CodeGenCXX/visibility-inlines-hidden.cpp2
-rw-r--r--test/CodeGenCXX/visibility.cpp32
-rw-r--r--test/CodeGenCXX/vla.cpp43
-rw-r--r--test/CodeGenCXX/volatile-1.cpp2
-rw-r--r--test/CodeGenCXX/vtable-pointer-initialization.cpp6
-rw-r--r--test/CodeGenCXX/x86_32-arguments.cpp2
-rw-r--r--test/CodeGenCXX/x86_64-arguments.cpp34
-rw-r--r--test/CodeGenObjC/arc-arm.m20
-rw-r--r--test/CodeGenObjC/arc-block-ivar-layout.m60
-rw-r--r--test/CodeGenObjC/arc-bridged-cast.m90
-rw-r--r--test/CodeGenObjC/arc-compound-stmt.m29
-rw-r--r--test/CodeGenObjC/arc-foreach.m72
-rw-r--r--test/CodeGenObjC/arc-ivar-layout.m44
-rw-r--r--test/CodeGenObjC/arc-no-runtime.m9
-rw-r--r--test/CodeGenObjC/arc-related-result-type.m30
-rw-r--r--test/CodeGenObjC/arc-unbridged-cast.m37
-rw-r--r--test/CodeGenObjC/arc-unopt.m69
-rw-r--r--test/CodeGenObjC/arc-weak-property.m55
-rw-r--r--test/CodeGenObjC/arc.m1554
-rw-r--r--test/CodeGenObjC/autorelease.m30
-rw-r--r--test/CodeGenObjC/block-6.m14
-rw-r--r--test/CodeGenObjC/blocks.m10
-rw-r--r--test/CodeGenObjC/debug-info-foreach.m20
-rw-r--r--test/CodeGenObjC/encode-test.m4
-rw-r--r--test/CodeGenObjC/exceptions-nonfragile.m16
-rw-r--r--test/CodeGenObjC/gc.m14
-rw-r--r--test/CodeGenObjC/mrr-autorelease.m24
-rw-r--r--test/CodeGenObjC/nonlazy-msgSend.m6
-rw-r--r--test/CodeGenObjC/property-list-in-class.m4
-rw-r--r--test/CodeGenObjC/related-result-type.m54
-rw-r--r--test/CodeGenObjC/terminate.m29
-rw-r--r--test/CodeGenObjC/variadic-sends.m8
-rw-r--r--test/CodeGenObjCXX/arc-globals.mm27
-rw-r--r--test/CodeGenObjCXX/arc-mangle.mm25
-rw-r--r--test/CodeGenObjCXX/arc-move.mm75
-rw-r--r--test/CodeGenObjCXX/arc-new-delete.mm95
-rw-r--r--test/CodeGenObjCXX/arc-pseudo-destructors.mm21
-rw-r--r--test/CodeGenObjCXX/arc-references.mm83
-rw-r--r--test/CodeGenObjCXX/arc-special-member-functions.mm161
-rw-r--r--test/CodeGenObjCXX/arc.mm166
-rw-r--r--test/CodeGenObjCXX/catch-id-type.mm48
-rw-r--r--test/CodeGenObjCXX/copy.mm26
-rw-r--r--test/CodeGenObjCXX/encode.mm14
-rw-r--r--test/CodeGenObjCXX/gc.mm20
-rw-r--r--test/CodeGenObjCXX/property-object-conditional-exp.mm7
-rw-r--r--test/CodeGenObjCXX/property-objects.mm2
-rw-r--r--test/CodeGenOpenCL/2011-04-15-vec-init-from-vec.cl7
-rw-r--r--test/CodeGenOpenCL/vector_literals_valid.cl22
-rw-r--r--test/Driver/arc-exceptions.m5
-rw-r--r--test/Driver/arc.c14
-rw-r--r--test/Driver/darwin-ld.c20
-rw-r--r--test/Driver/darwin-objc-options.m2
-rw-r--r--test/Driver/darwin-xarch.c6
-rw-r--r--test/Driver/gnu-runtime.m5
-rw-r--r--test/Driver/ios-simulator-arcruntime.c6
-rw-r--r--test/Driver/mg.c5
-rw-r--r--test/Driver/no-objc-arr.m8
-rw-r--r--test/Driver/noexecstack.c1
-rw-r--r--test/Driver/rewrite-objc.m2
-rw-r--r--test/Driver/sysroot.c6
-rw-r--r--test/Driver/x86_features.c4
-rw-r--r--test/FixIt/fixit-objc.m14
-rw-r--r--test/FixIt/fixit.c5
-rw-r--r--test/FixIt/typo-crash.cpp11
-rw-r--r--test/FixIt/typo.cpp12
-rw-r--r--test/Frontend/dependency-gen.c34
-rw-r--r--test/Index/annotate-tokens-pp.c14
-rw-r--r--test/Index/annotate-tokens.cpp8
-rw-r--r--test/Index/annotate-tokens.m28
-rw-r--r--test/Index/arc-annotate.m38
-rw-r--r--test/Index/arc-complete.m16
-rw-r--r--test/Index/c-index-api-loadTU-test.m11
-rw-r--r--test/Index/c-index-getCursor-pp.c8
-rw-r--r--test/Index/c-index-getCursor-test.m2
-rw-r--r--test/Index/code-completion.cpp20
-rw-r--r--test/Index/complete-exprs.m9
-rw-r--r--test/Index/complete-natural.m5
-rw-r--r--test/Index/complete-property-flags.m2
-rw-r--r--test/Index/get-cursor.cpp7
-rw-r--r--test/Index/nested-macro-instantiations.cpp10
-rw-r--r--test/Index/werror.c15
-rw-r--r--test/Lexer/has_feature_objc_arc.m20
-rw-r--r--test/Makefile2
-rw-r--r--test/Misc/caret-diags-macros.c107
-rw-r--r--test/Misc/diag-aka-types.cpp38
-rw-r--r--test/Misc/include-stack-for-note-flag.cpp4
-rw-r--r--test/Misc/macro-backtrace-limit.c12
-rw-r--r--test/PCH/Inputs/arc.h20
-rw-r--r--test/PCH/Inputs/typo.hpp8
-rw-r--r--test/PCH/arc.m9
-rw-r--r--test/PCH/typo.cpp17
-rw-r--r--test/PCH/variables.c34
-rw-r--r--test/PCH/variables.h1
-rw-r--r--test/Parser/MicrosoftExtensions.c2
-rw-r--r--test/Parser/parenthesis-balance.cpp15
-rw-r--r--test/Parser/recovery.c14
-rw-r--r--test/Parser/switch-recovery.cpp14
-rw-r--r--test/Preprocessor/include-directive2.c2
-rw-r--r--test/Preprocessor/init.c2
-rw-r--r--test/Preprocessor/macro_paste_bad.c1
-rw-r--r--test/Preprocessor/macro_paste_hashhash.c6
-rw-r--r--test/Preprocessor/macro_paste_simple.c13
-rw-r--r--test/Preprocessor/pragma_diagnostic_output.c26
-rw-r--r--test/Preprocessor/warn-macro-unused.c5
-rw-r--r--test/Preprocessor/warn-macro-unused.h1
-rw-r--r--test/Sema/arm-neon-types.c7
-rw-r--r--test/Sema/asm.c20
-rw-r--r--test/Sema/attr-deprecated.c2
-rw-r--r--test/Sema/attr-naked.c4
-rw-r--r--test/Sema/attr-unavailable-message.c10
-rw-r--r--test/Sema/attr-weak.c4
-rw-r--r--test/Sema/bitfield.c1
-rw-r--r--test/Sema/compare.c15
-rw-r--r--test/Sema/const-eval.c2
-rw-r--r--test/Sema/conversion-64-32.c10
-rw-r--r--test/Sema/conversion.c8
-rw-r--r--test/Sema/ext_vector_casts.c2
-rw-r--r--test/Sema/extern-redecl.c15
-rw-r--r--test/Sema/format-strings.c14
-rw-r--r--test/Sema/i-c-e.c2
-rw-r--r--test/Sema/incomplete-decl.c2
-rw-r--r--test/Sema/inline-redef.c24
-rw-r--r--test/Sema/inline.c18
-rw-r--r--test/Sema/no-format-y2k-turnsoff-format.c9
-rw-r--r--test/Sema/nonnull.c21
-rw-r--r--test/Sema/paren-list-expr-type.cpp17
-rw-r--r--test/Sema/parentheses.c30
-rw-r--r--test/Sema/parentheses.cpp38
-rw-r--r--test/Sema/pointer-addition.c25
-rw-r--r--test/Sema/pointer-subtract-compat.c2
-rw-r--r--test/Sema/shift.c2
-rw-r--r--test/Sema/sign-conversion.c8
-rw-r--r--test/Sema/struct-decl.c2
-rw-r--r--test/Sema/typecheck-binop.c6
-rw-r--r--test/Sema/typedef-variable-type.c2
-rw-r--r--test/Sema/uninit-variables.c15
-rw-r--r--test/Sema/varargs.c15
-rw-r--r--test/Sema/vla.c4
-rw-r--r--test/Sema/warn-sizeof-arrayarg.c30
-rw-r--r--test/Sema/x86-builtin-palignr.c4
-rw-r--r--test/SemaCXX/PR10243.cpp23
-rw-r--r--test/SemaCXX/PR7410.cpp13
-rw-r--r--test/SemaCXX/PR9459.cpp2
-rw-r--r--test/SemaCXX/alignof-sizeof-reference.cpp6
-rw-r--r--test/SemaCXX/attr-unavailable.cpp9
-rw-r--r--test/SemaCXX/c99-variable-length-array.cpp9
-rw-r--r--test/SemaCXX/condition.cpp5
-rw-r--r--test/SemaCXX/conversion-function.cpp14
-rw-r--r--test/SemaCXX/copy-assignment.cpp18
-rw-r--r--test/SemaCXX/crashes.cpp9
-rw-r--r--test/SemaCXX/decltype.cpp5
-rw-r--r--test/SemaCXX/enum-scoped.cpp23
-rw-r--r--test/SemaCXX/expressions.cpp22
-rw-r--r--test/SemaCXX/for-range-unused.cpp21
-rw-r--r--test/SemaCXX/function-overload-typo-crash.cpp12
-rw-r--r--test/SemaCXX/generalized-initializers.cpp62
-rw-r--r--test/SemaCXX/i-c-e-cxx.cpp13
-rw-r--r--test/SemaCXX/member-init.cpp4
-rw-r--r--test/SemaCXX/member-pointer.cpp16
-rw-r--r--test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp72
-rw-r--r--test/SemaCXX/nested-name-spec.cpp21
-rw-r--r--test/SemaCXX/new-delete.cpp8
-rw-r--r--test/SemaCXX/null_in_arithmetic_ops.cpp93
-rw-r--r--test/SemaCXX/nullptr_in_arithmetic_ops.cpp73
-rw-r--r--test/SemaCXX/overloaded-name.cpp16
-rw-r--r--test/SemaCXX/return.cpp11
-rw-r--r--test/SemaCXX/vararg-non-pod.cpp18
-rw-r--r--test/SemaCXX/vector.cpp8
-rw-r--r--test/SemaCXX/virtuals.cpp29
-rw-r--r--test/SemaCXX/warn-bad-memaccess.cpp42
-rw-r--r--test/SemaCXX/warn-memset-bad-sizeof.cpp101
-rw-r--r--test/SemaCXX/warn-pure-virtual-call-from-ctor-dtor.cpp7
-rw-r--r--test/SemaCXX/warn-unused-variables.cpp26
-rw-r--r--test/SemaObjC/Inputs/arc-system-header.h52
-rw-r--r--test/SemaObjC/arc-bridged-cast.m43
-rw-r--r--test/SemaObjC/arc-decls.m64
-rw-r--r--test/SemaObjC/arc-jump-block.m84
-rw-r--r--test/SemaObjC/arc-no-runtime.m15
-rw-r--r--test/SemaObjC/arc-non-pod-memaccess.m55
-rw-r--r--test/SemaObjC/arc-peformselector.m38
-rw-r--r--test/SemaObjC/arc-property-decl-attrs.m67
-rw-r--r--test/SemaObjC/arc-property-lifetime.m112
-rw-r--r--test/SemaObjC/arc-property.m48
-rw-r--r--test/SemaObjC/arc-system-header.m50
-rw-r--r--test/SemaObjC/arc-type-conversion.m77
-rw-r--r--test/SemaObjC/arc-unavailable-for-weakref.m47
-rw-r--r--test/SemaObjC/arc-unbridged-cast.m18
-rw-r--r--test/SemaObjC/arc-unsafe-assigns.m41
-rw-r--r--test/SemaObjC/arc-unsafe_unretained.m12
-rw-r--r--test/SemaObjC/arc.m628
-rw-r--r--test/SemaObjC/autoreleasepool.m22
-rw-r--r--test/SemaObjC/class-proto-1.m4
-rw-r--r--test/SemaObjC/class-unavail-warning.m2
-rw-r--r--test/SemaObjC/debugger-support.m14
-rw-r--r--test/SemaObjC/error-property-gc-attr.m4
-rw-r--r--test/SemaObjC/forward-class-1.m15
-rw-r--r--test/SemaObjC/ivar-ref-misuse.m5
-rw-r--r--test/SemaObjC/method-lookup-3.m16
-rw-r--r--test/SemaObjC/no-warning-unavail-unimp.m12
-rw-r--r--test/SemaObjC/property-10.m17
-rw-r--r--test/SemaObjC/property-inherited.m4
-rw-r--r--test/SemaObjC/property-ns-returns-not-retained-attr.m21
-rw-r--r--test/SemaObjC/related-result-type-inference.m2
-rw-r--r--test/SemaObjC/selector-3.m25
-rw-r--r--test/SemaObjC/self-declared-in-block.m15
-rw-r--r--test/SemaObjC/sizeof-interface.m2
-rw-r--r--test/SemaObjC/special-dep-unavail-warning.m10
-rw-r--r--test/SemaObjC/synthesized-ivar.m8
-rw-r--r--test/SemaObjC/typedef-class.m2
-rw-r--r--test/SemaObjC/undef-superclass-1.m6
-rw-r--r--test/SemaObjC/warn-retain-cycle.m91
-rw-r--r--test/SemaObjC/weak-property.m24
-rw-r--r--test/SemaObjCXX/Inputs/arc-system-header.h14
-rw-r--r--test/SemaObjCXX/arc-0x.mm32
-rw-r--r--test/SemaObjCXX/arc-bool-conversion.mm7
-rw-r--r--test/SemaObjCXX/arc-bridged-cast.mm36
-rw-r--r--test/SemaObjCXX/arc-libcxx.mm11
-rw-r--r--test/SemaObjCXX/arc-libstdcxx.mm10
-rw-r--r--test/SemaObjCXX/arc-memfunc.mm15
-rw-r--r--test/SemaObjCXX/arc-non-pod.mm116
-rw-r--r--test/SemaObjCXX/arc-object-init-destroy.mm52
-rw-r--r--test/SemaObjCXX/arc-overloading.mm175
-rw-r--r--test/SemaObjCXX/arc-system-header.mm10
-rw-r--r--test/SemaObjCXX/arc-templates.mm254
-rw-r--r--test/SemaObjCXX/arc-type-conversion.mm221
-rw-r--r--test/SemaObjCXX/arc-type-traits.mm90
-rw-r--r--test/SemaObjCXX/arc-unavailable-for-weakref.mm47
-rw-r--r--test/SemaObjCXX/exceptions-fragile.mm2
-rw-r--r--test/SemaObjCXX/gc-attributes.mm4
-rw-r--r--test/SemaObjCXX/null_objc_pointer.mm13
-rw-r--r--test/SemaObjCXX/nullptr.mm5
-rw-r--r--test/SemaObjCXX/property-type-mismatch.mm19
-rw-r--r--test/SemaObjCXX/related-result-type-inference.mm2
-rw-r--r--test/SemaOpenCL/vector_literals_invalid.cl13
-rw-r--r--test/SemaTemplate/class-template-decl.cpp2
-rw-r--r--test/SemaTemplate/deduction.cpp12
-rw-r--r--test/SemaTemplate/default-arguments.cpp15
-rw-r--r--test/SemaTemplate/dependent-names-no-std.cpp2
-rw-r--r--test/SemaTemplate/dependent-names.cpp42
-rw-r--r--test/SemaTemplate/ext-vector-type.cpp34
-rw-r--r--test/SemaTemplate/instantiate-call.cpp2
-rw-r--r--test/SemaTemplate/instantiate-function-2.cpp33
-rw-r--r--test/SemaTemplate/instantiate-member-class.cpp14
-rw-r--r--test/SemaTemplate/instantiate-try-catch.cpp17
-rw-r--r--test/SemaTemplate/member-inclass-init-value-dependent.cpp11
-rw-r--r--test/SemaTemplate/unresolved-construct.cpp19
-rw-r--r--test/Unit/lit.cfg18
-rw-r--r--tools/CMakeLists.txt2
-rw-r--r--tools/Makefile4
-rw-r--r--tools/arcmt-test/CMakeLists.txt13
-rw-r--r--tools/arcmt-test/Makefile24
-rw-r--r--tools/arcmt-test/arcmt-test.cpp374
-rw-r--r--tools/c-arcmt-test/CMakeLists.txt14
-rw-r--r--tools/c-arcmt-test/Makefile25
-rw-r--r--tools/c-arcmt-test/c-arcmt-test.c91
-rw-r--r--tools/c-index-test/Makefile4
-rw-r--r--tools/c-index-test/c-index-test.c109
-rw-r--r--tools/driver/CMakeLists.txt1
-rw-r--r--tools/driver/Makefile2
-rw-r--r--tools/driver/cc1_main.cpp2
-rw-r--r--tools/driver/cc1as_main.cpp24
-rw-r--r--tools/driver/driver.cpp8
-rw-r--r--tools/libclang/ARCMigrate.cpp98
-rw-r--r--tools/libclang/CIndex.cpp125
-rw-r--r--tools/libclang/CIndexCodeCompletion.cpp192
-rw-r--r--tools/libclang/CMakeLists.txt3
-rw-r--r--tools/libclang/CXCursor.cpp23
-rw-r--r--tools/libclang/CXCursor.h13
-rw-r--r--tools/libclang/CXType.cpp6
-rw-r--r--tools/libclang/Makefile5
-rw-r--r--tools/libclang/libclang.darwin.exports6
-rw-r--r--tools/libclang/libclang.exports6
-rwxr-xr-xtools/scan-build/ccc-analyzer19
-rw-r--r--unittests/Basic/FileManagerTest.cpp6
-rw-r--r--unittests/Frontend/Makefile4
-rw-r--r--www/compatibility.html4
788 files changed, 45084 insertions, 11164 deletions
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 = "<group>"; };
90FD6D91103C3D80005F5B73 /* Utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Utils.h; path = clang/Frontend/Utils.h; sourceTree = "<group>"; };
90FD6DB5103D977E005F5B73 /* index-test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "index-test.cpp"; path = "tools/index-test/index-test.cpp"; sourceTree = "<group>"; };
+ BB20603B131EDDBF003C3343 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = "<group>"; };
+ BB20603C131EDDBF003C3343 /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = "<group>"; };
+ BB206041131EDDDA003C3343 /* ARRMT.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARRMT.h; sourceTree = "<group>"; };
+ BB206043131EDE03003C3343 /* arrmt-test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "arrmt-test.cpp"; sourceTree = "<group>"; };
+ BB206044131EDE03003C3343 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = "<group>"; };
+ BB206045131EDE03003C3343 /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = "<group>"; };
BB5C372812A5057500259F53 /* DumpXML.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DumpXML.cpp; path = /Volumes/Data/llvm/tools/clang/lib/AST/DumpXML.cpp; sourceTree = "<absolute>"; };
BBA5AB141309C2FA000B38F1 /* AdjustedReturnValueChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AdjustedReturnValueChecker.cpp; sourceTree = "<group>"; };
BBA5AB151309C2FA000B38F1 /* AnalyzerStatsChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AnalyzerStatsChecker.cpp; sourceTree = "<group>"; };
@@ -561,7 +567,6 @@
BF9FEE321225E898003A8B71 /* ItaniumCXXABI.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ItaniumCXXABI.cpp; path = lib/CodeGen/ItaniumCXXABI.cpp; sourceTree = "<group>"; };
BF9FEE341225E8B1003A8B71 /* MicrosoftCXXABI.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MicrosoftCXXABI.cpp; path = lib/CodeGen/MicrosoftCXXABI.cpp; sourceTree = "<group>"; };
BF9FEE361225E8CF003A8B71 /* README.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = README.txt; path = lib/CodeGen/README.txt; sourceTree = "<group>"; };
- BF9FEE371225E925003A8B71 /* BoostConAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BoostConAction.cpp; path = lib/Frontend/BoostConAction.cpp; sourceTree = "<group>"; };
BF9FEE451225EA24003A8B71 /* DelayedDiagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DelayedDiagnostic.h; path = clang/Sema/DelayedDiagnostic.h; sourceTree = "<group>"; };
BF9FEE511226FE9F003A8B71 /* ParseAST.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ParseAST.cpp; path = lib/Parse/ParseAST.cpp; sourceTree = "<group>"; };
BF9FEE531226FEC1003A8B71 /* RAIIObjectsForParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RAIIObjectsForParser.h; path = lib/Parse/RAIIObjectsForParser.h; sourceTree = "<group>"; };
@@ -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 = "<group>";
};
+ BB20603A131EDDBF003C3343 /* ARRMigrate */ = {
+ isa = PBXGroup;
+ children = (
+ BB20603B131EDDBF003C3343 /* CMakeLists.txt */,
+ BB20603C131EDDBF003C3343 /* Makefile */,
+ BDDF60E91337BF40009F1764 /* Transforms.cpp */,
+ );
+ name = ARRMigrate;
+ path = lib/ARRMigrate;
+ sourceTree = "<group>";
+ };
+ BB206040131EDDDA003C3343 /* ARRMigrate */ = {
+ isa = PBXGroup;
+ children = (
+ BB206041131EDDDA003C3343 /* ARRMT.h */,
+ );
+ name = ARRMigrate;
+ path = clang/ARRMigrate;
+ sourceTree = "<group>";
+ };
+ BB206042131EDE03003C3343 /* arrmt-test */ = {
+ isa = PBXGroup;
+ children = (
+ BD8A47E7133D32660066FE40 /* ARRMT.cpp */,
+ BB206043131EDE03003C3343 /* arrmt-test.cpp */,
+ BB206044131EDE03003C3343 /* CMakeLists.txt */,
+ BB206045131EDE03003C3343 /* Makefile */,
+ );
+ name = "arrmt-test";
+ path = "tools/arrmt-test";
+ sourceTree = "<group>";
+ };
BBA5AB121309C2FA000B38F1 /* StaticAnalyzer */ = {
isa = PBXGroup;
children = (
@@ -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 @@
+<html>
+<head>
+<title>Objective-C Automatic Reference Counting (ARC)</title>
+<link type="text/css" rel="stylesheet" href="../menu.css" />
+<link type="text/css" rel="stylesheet" href="../content.css" />
+<style type="text/css">
+/* Collapse the items in the ToC to the left. */
+div#toc ul {
+ padding-left: 0
+}
+
+/* Rationales appear in italic. */
+div.rationale {
+ font-style: italic
+}
+
+div.rationale em {
+ font-style: normal
+}
+
+div h1 { font-size: 2em; margin: .67em 0 }
+div div h1 { font-size: 1.5em; margin: .75em 0 }
+div div div h1 { font-size: 1.17em; margin: .83em 0 }
+div div div div h1 { margin: 1.12em 0 }
+
+span.term { font-style: italic; font-weight: bold }
+</style>
+
+<script lang="javascript">
+/// A little script to recursively build a table of contents.
+function buildTOC(div, toc, ancestry) {
+ var children = div.childNodes;
+ var len = children.length;
+
+ var childNumber = 0;
+
+ var list = null;
+ for (var i = 0; i < len; ++i) {
+ var child = children[i];
+ if (child.nodeName != "DIV") continue;
+ if (child.getAttribute("class") == "rationale") continue;
+ if (child.id == "toc") continue;
+
+ // Okay, we're actually going to build a list node.
+ if (list === null) list = document.createElement("ul");
+
+ var childAncestry = ancestry + ++childNumber + ".";
+
+ var headerNode = child.childNodes[1];
+ var title = headerNode.innerHTML;
+ headerNode.insertBefore(document.createTextNode(childAncestry + " "),
+ headerNode.firstChild);
+
+ var item = document.createElement("li");
+ item.appendChild(document.createTextNode(childAncestry + " "));
+
+ var anchor = document.createElement("a");
+ anchor.href = "#" + child.id;
+ anchor.innerHTML = title;
+ item.appendChild(anchor);
+
+ buildTOC(child, item, childAncestry);
+
+ list.appendChild(item);
+ }
+ if (list) toc.appendChild(list);
+}
+
+function onLoad() {
+ var toc = document.getElementById("toc");
+ var content = document.getElementById("content");
+ buildTOC(content, toc, "");
+}
+window.onload = onLoad;
+
+</script>
+</head>
+<body>
+
+<!--#include virtual="../menu.html.incl"-->
+
+<div id="content">
+<h1>Automatic Reference Counting</h1>
+
+<div id="toc">
+</div>
+
+<div id="meta">
+<h1>About this document</h1>
+
+<div id="meta.purpose">
+<h1>Purpose</h1>
+
+<p>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.</p>
+
+<p>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.</p>
+
+</div> <!-- meta.purpose -->
+
+<div id="meta.background">
+<h1>Background</h1>
+
+<p>This document assumes a basic familiarity with C.</p>
+
+<p><span class="term">Blocks</span> are a C language extension for
+creating anonymous functions. Users interact with and transfer block
+objects using <span class="term">block pointers</span>, 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 <tt>Block_copy</tt> 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 <tt>Block_release</tt>,
+which decreases the reference count by 1 and destroys the object if
+the count reaches zero and is on the heap.</p>
+
+<p>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.</p>
+
+<p>Objective-C defines a new type kind, collectively called
+the <span class="term">object pointer types</span>. This kind has two
+notable builtin members, <tt>id</tt> and <tt>Class</tt>; <tt>id</tt>
+is the final supertype of all object pointers. The validity of
+conversions between object pointer types is not checked at runtime.
+Users may define <span class="term">classes</span>; 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 <span class="term">ivars</span>, fields which appear on all
+instances of that class. For every class <i>T</i> there's an
+associated metaclass; it has no fields, its superclass is the
+metaclass of <i>T</i>'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 <tt>Class</tt>.</p>
+
+<p>A class declaration (<tt>@interface</tt>) declares a set
+of <span class="term">methods</span>. A method has a return type, a
+list of argument types, and a <span class="term">selector</span>: a
+name like <tt>foo:bar:baz:</tt>, 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 <span class="term">receiver</span>) and a list of formal
+arguments interspersed with the selector, like so:</p>
+
+<pre>[receiver foo: fooArg bar: barArg baz: bazArg]</pre>
+
+<p>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 <q>expression</q> 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 <tt>super</tt>, 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
+<tt>@interface</tt>, but those defined in a separate
+<tt>@implementation</tt> declaration; however, when compiling a
+call, typechecking is done based on the methods declared in the
+<tt>@interface</tt>.</p>
+
+<p>Method declarations may also be grouped into
+<span class="term">protocols</span>, 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.</p>
+
+<p><span class="term">Class extensions</span> are collections of ivars
+and methods, designed to allow a class's <tt>@interface</tt> to be
+split across multiple files; however, there is still a primary
+implementation file which must see the <tt>@interface</tt>s of all
+class extensions.
+<span class="term">Categories</span> allow methods (but not ivars) to
+be declared <i>post hoc</i> on an arbitrary class; the methods in the
+category's <tt>@implementation</tt> 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.</p>
+
+<p>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: <tt>retain</tt> increases the object's reference count by
+1, whereas <tt>release</tt> decreases it by 1 and calls the instance
+method <tt>dealloc</tt> if the count reaches 0. To simplify certain
+operations, there is also an <span class="term">autorelease
+pool</span>, a thread-local list of objects to call <tt>release</tt>
+on later; an object can be added to this pool by
+calling <tt>autorelease</tt> on it.</p>
+
+<p>Block pointers may be converted to type <tt>id</tt>; 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 <tt>retain</tt> by
+adjusting the reference count, not by calling <tt>Block_copy</tt>.</p>
+
+</div> <!-- meta.background -->
+
+</div> <!-- meta -->
+
+<div id="general">
+<h1>General</h1>
+
+<p>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.</p>
+
+<p>ARC may be explicitly enabled with the compiler
+flag <tt>-fobjc-arc</tt>. It may also be explicitly disabled with the
+compiler flag <tt>-fno-objc-arc</tt>. The last of these two flags
+appearing on the compile line <q>wins</q>.</p>
+
+<p>If ARC is enabled, <tt>__has_feature(objc_arc)</tt> will expand to
+1 in the preprocessor. For more information about <tt>__has_feature</tt>,
+see the <a href="LanguageExtensions.html#__has_feature_extension">language
+extensions</a> document.</p>
+
+</div>
+
+<div id="objects">
+<h1>Retainable object pointers</h1>
+
+<p>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 <em>values</em>
+(patterns of bits indicating the location of a pointed-to object), not
+pointer
+<em>objects</em> (locations in memory which store pointer values).
+The rules for objects are covered in the next section.</p>
+
+<p>A <span class="term">retainable object pointer</span>
+(or <q>retainable pointer</q>) is a value of
+a <span class="term">retainable object pointer type</span>
+(<q>retainable type</q>). There are three kinds of retainable object
+pointer types:</p>
+<ul>
+<li>block pointers (formed by applying the caret (<tt>^</tt>)
+declarator sigil to a function type)</li>
+<li>Objective-C object pointers (<tt>id</tt>, <tt>Class</tt>, <tt>NSFoo*</tt>, etc.)</li>
+<li>typedefs marked with <tt>__attribute__((NSObject))</tt></li>
+</ul>
+
+<p>Other pointer types, such as <tt>int*</tt> and <tt>CFStringRef</tt>,
+are not subject to ARC's semantics and restrictions.</p>
+
+<div class="rationale">
+
+<p>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:</p>
+
+<ul>
+<li>The type system must reliably identify which objects are to be
+managed. An <tt>int*</tt> might be a pointer to a <tt>malloc</tt>'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.</li>
+<li>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.</li>
+<li>There must be reliable conventions for whether and
+when <q>ownership</q> 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.</li>
+</ul>
+</div> <!-- rationale -->
+
+<p>The use of <tt>__attribute__((NSObject))</tt> 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 <tt>__typeof</tt> and C++
+template argument substitution.</p>
+
+<div class="rationale"><p>Rationale: any compiler operation which
+incidentally strips type <q>sugar</q> from a type will yield a type
+without the attribute, which may result in unexpected
+behavior.</p></div>
+
+<div id="objects.retains">
+<h1>Retain count semantics</h1>
+
+<p>A retainable object pointer is either a <span class="term">null
+pointer</span> or a pointer to a valid object. Furthermore, if it has
+block pointer type and is not <tt>null</tt> then it must actually be a
+pointer to a block object, and if it has <tt>Class</tt> 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.</p>
+
+<p>For ARC's purposes, a valid object is one with <q>well-behaved</q>
+retaining operations. Specifically, the object must be laid out such
+that the Objective-C message send machinery can successfully send it
+the following messages:</p>
+
+<ul>
+<li><tt>retain</tt>, taking no arguments and returning a pointer to
+the object.</li>
+<li><tt>release</tt>, taking no arguments and returning <tt>void</tt>.</li>
+<li><tt>autorelease</tt>, taking no arguments and returning a pointer
+to the object.</li>
+</ul>
+
+<p>The behavior of these methods is constrained in the following ways.
+The term <span class="term">high-level semantics</span> 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 <tt>retain</tt>, 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.</p>
+
+<p>It is undefined behavior if a computation history featuring a send
+of <tt>retain</tt> followed by a send of <tt>release</tt> to the same
+object, with no intervening <tt>release</tt> 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.</p>
+
+<p>It is undefined behavior if a computation history features any use
+whatsoever of an object following the completion of a send
+of <tt>release</tt> that is not preceded by a send of <tt>retain</tt>
+to the same object.</p>
+
+<p>The behavior of <tt>autorelease</tt> must be equivalent to sending
+<tt>release</tt> when one of the autorelease pools currently in scope
+is popped. It may not throw an exception.</p>
+
+<p>When the semantics call for performing one of these operations on a
+retainable object pointer, if that pointer is <tt>null</tt> then the
+effect is a no-op.</p>
+
+<p>All of the semantics described in this document are subject to
+additional <a href="#optimization">optimization rules</a> 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.</p>
+
+</div> <!-- objects.retains -->
+
+<div id="objects.operands">
+<h1>Retainable object pointers as operands and arguments</h1>
+
+<p>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:</p>
+<ul>
+<li>loading a retainable pointer from an object with non-weak
+<a href="#ownership">ownership</a>,</li>
+<li>passing a retainable pointer as an argument to a function or
+method, and</li>
+<li>receiving a retainable pointer as the result of a function or
+method call.</li>
+</ul>
+
+<div class="rationale"><p>Rationale: while this might seem
+uncontroversial, it is actually unsafe when multiple expressions are
+evaluated in <q>parallel</q>, 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.</p></div>
+
+<p>The remainder of this section describes exceptions to these rules,
+how those exceptions are detected, and what those exceptions imply
+semantically.</p>
+
+<div id="objects.operands.consumed">
+<h1>Consumed parameters</h1>
+
+<p>A function or method parameter of retainable object pointer type
+may be marked as <span class="term">consumed</span>, signifying that
+the callee expects to take ownership of a +1 retain count. This is
+done by adding the <tt>ns_consumed</tt> attribute to the parameter
+declaration, like so:</p>
+
+<pre>void foo(__attribute((ns_consumed)) id x);
+- (void) foo: (id) __attribute((ns_consumed)) x;</pre>
+
+<p>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.</p>
+
+<p>When passing such an argument, ARC retains the argument prior to
+making the call.</p>
+
+<p>When receiving such an argument, ARC releases the argument at the
+end of the function, subject to the usual optimizations for local
+values.</p>
+
+<div class="rationale"><p>Rationale: this formalizes direct transfers
+of ownership from a caller to a callee. The most common scenario here
+is passing the <tt>self</tt> parameter to <tt>init</tt>, 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.</p></div>
+
+<p>The implicit <tt>self</tt> parameter of a method may be marked as
+consumed by adding <tt>__attribute__((ns_consumes_self))</tt> to the
+method declaration. Methods in the <tt>init</tt>
+<a href="#family">family</a> are treated as if they were implicitly
+marked with this attribute.</p>
+
+<p>It is undefined behavior if an Objective-C message send to a method
+with <tt>ns_consumed</tt> 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 <tt>ns_consumed</tt> 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 <tt>ns_consumed</tt>
+parameters than the implementation of the called block or function.</p>
+
+<div class="rationale"><p>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.</p></div>
+
+</div>
+
+<div id="objects.operands.retained_returns">
+<h1>Retained return values</h1>
+
+<p>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 <tt>ns_returns_retained</tt> attribute to the function or
+method declaration, like so:</p>
+
+<pre>id foo(void) __attribute((ns_returns_retained));
+- (id) foo __attribute((ns_returns_retained));</pre>
+
+<p>This attribute is part of the type of the function or method.</p>
+
+<p>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.</p>
+
+<p>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.</p>
+
+<div class="rationale"><p>Rationale: this formalizes direct transfers of
+ownership from a callee to a caller. The most common scenario this
+models is the retained return from <tt>init</tt>, <tt>alloc</tt>,
+<tt>new</tt>, and <tt>copy</tt> methods, but there are other cases in
+the frameworks. After optimization there are typically no extra
+retains and releases required.</p></div>
+
+<p>Methods in
+the <tt>alloc</tt>, <tt>copy</tt>, <tt>init</tt>, <tt>mutableCopy</tt>,
+and <tt>new</tt> <a href="#family">families</a> are implicitly marked
+<tt>__attribute__((ns_returns_retained))</tt>. This may be suppressed
+by explicitly marking the
+method <tt>__attribute__((ns_returns_not_retained))</tt>.</p>
+</div>
+
+<p>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.</p>
+
+<div class="rationale"><p>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.</p></div>
+
+
+<div id="objects.operands.other-returns">
+<h1>Unretained return values</h1>
+
+<p>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.</p>
+
+<p>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 <tt>autorelease</tt>, but callers must not assume that the
+value is actually in the autorelease pool.</p>
+
+<p>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.</p>
+
+<div class="rationale"><p>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.</p></div>
+
+<p>A method or function may be marked
+with <tt>__attribute__((ns_returns_autoreleased))</tt> 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.</p>
+</div>
+
+<div id="objects.operands.casts">
+<h1>Bridged casts</h1>
+
+<p>A <span class="term">bridged cast</span> is a C-style cast
+annotated with one of three keywords:</p>
+
+<ul>
+<li><tt>(__bridge T) op</tt> casts the operand to the destination
+type <tt>T</tt>. If <tt>T</tt> is a retainable object pointer type,
+then <tt>op</tt> must have a non-retainable pointer type.
+If <tt>T</tt> is a non-retainable pointer type, then <tt>op</tt> 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.</li>
+
+<li><tt>(__bridge_retained T) op</tt> 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.</li>
+
+<li><tt>(__bridge_transfer T) op</tt> 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.</li>
+</ul>
+
+<p>These casts are required in order to transfer objects in and out of
+ARC control; see the rationale in the section
+on <a href="#objects.restrictions.conversion">conversion of retainable
+object pointers</a>.</p>
+
+<p>Using a <tt>__bridge_retained</tt> or <tt>__bridge_transfer</tt>
+cast purely to convince ARC to emit an unbalanced retain or release,
+respectively, is poor form.</p>
+
+</div>
+
+</div>
+
+<div id="objects.restrictions">
+<h1>Restrictions</h1>
+
+<div id="objects.restrictions.conversion">
+<h1>Conversion of retainable object pointers</h1>
+
+<p>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 <tt>void*</tt>.
+As an exception, cast to <tt>intptr_t</tt> is allowed becuase such
+casts are not transferring ownership. The <a href="#objects.operands.casts">bridged
+casts</a> may be used to perform these conversions where
+necessary.</p>
+
+<div class="rationale"><p>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.</p></div>
+</div>
+
+<p>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 <tt>__bridge_transfer</tt> cast
+if:</p>
+
+<ul>
+<li>the method has the <tt>cf_returns_retained</tt> attribute, or if
+not that,</li>
+<li>the method does not have the <tt>cf_returns_not_retained</tt>
+attribute and</li>
+<li>the method's <a href="#family">selector family</a> would imply
+the <tt>ns_returns_retained</tt> attribute on a method which returned
+a retainable object pointer type.</li>
+</ul>
+
+<p>Otherwise the cast is treated as a <tt>__bridge</tt> cast.</p>
+
+</div>
+
+</div>
+
+<div id="ownership">
+<h1>Ownership qualification</h1>
+
+<p>This section describes the behavior of <em>objects</em> of
+retainable object pointer type; that is, locations in memory which
+store retainable object pointers.</p>
+
+<p>A type is a <span class="term">retainable object owner type</span>
+if it is a retainable object pointer type or an array type whose
+element type is a retainable object owner type.</p>
+
+<p>An <span class="term">ownership qualifier</span> 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.</p>
+
+<p>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.</p>
+
+<p>Except as described under
+the <a href="#ownership.inference">inference rules</a>, 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.</p>
+
+<div class="rationale"><p>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 <a href="#ownership.inference.template_arguments">inference of <tt>__strong</tt> for template type arguments</a>. </p></div>
+
+<p>There are four ownership qualifiers:</p>
+
+<ul>
+<li><tt>__autoreleasing</tt></li>
+<li><tt>__strong</tt></li>
+<li><tt>__unsafe_unretained</tt></li>
+<li><tt>__weak</tt></li>
+</ul>
+
+<p>A type is <span class="term">nontrivially ownership-qualified</span>
+if it is qualified with <tt>__autoreleasing</tt>, <tt>__strong</tt>, or
+<tt>__weak</tt>.</p>
+
+<div id="ownership.spelling">
+<h1>Spelling</h1>
+
+<p>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.</p>
+
+<p>An ownership qualifier may be written anywhere that any other type
+qualifier may be written.</p>
+
+<p>If an ownership qualifier appears in
+the <i>declaration-specifiers</i>, the following rules apply:</p>
+
+<ul>
+<li>if the type specifier is a retainable object owner type, the
+qualifier applies to that type;</li>
+<li>if the outermost non-array part of the declarator is a pointer or
+block pointer, the qualifier applies to that type;</li>
+<li>otherwise the program is ill-formed.</li>
+</ul>
+
+<p>If an ownership qualifier appears on the declarator name, or on the
+declared object, it is applied to outermost pointer or block-pointer
+type.</p>
+
+<p>If an ownership qualifier appears anywhere else in a declarator, it
+applies to the type there.</p>
+
+<div id="ownership.spelling.property">
+<h1>Property declarations</h1>
+
+<p>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 <tt>__autoreleasing</tt>
+ownership.</p>
+
+<ul>
+<li><tt>assign</tt> implies <tt>__unsafe_unretained</tt> ownership.</li>
+<li><tt>copy</tt> implies <tt>__strong</tt> ownership, as well as the
+ usual behavior of copy semantics on the setter.</li>
+<li><tt>retain</tt> implies <tt>__strong</tt> ownership.</li>
+<li><tt>strong</tt> implies <tt>__strong</tt> ownership.</li>
+<li><tt>unsafe_unretained</tt> implies <tt>__unsafe_unretained</tt>
+ ownership.</li>
+<li><tt>weak</tt> implies <tt>__weak</tt> ownership.</li>
+</ul>
+
+<p>With the exception of <tt>weak</tt>, these modifiers are available
+in non-ARC modes.</p>
+
+<p>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
+<span class="term">associated instance variable</span> is the
+instance variable which is named, possibly implicitly, by the
+<tt>@synthesize</tt> 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.</p>
+
+</div> <!-- ownership.spelling.property -->
+
+</div> <!-- ownership.spelling -->
+
+<div id="ownership.semantics">
+<h1>Semantics</h1>
+
+<p>There are five <span class="term">managed operations</span> 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.</p>
+
+<p>A load or store with <q>primitive semantics</q> has the same
+semantics as the respective operation would have on an <tt>void*</tt>
+lvalue with the same alignment and non-ownership qualification.</p>
+
+<p><span class="term">Reading</span> occurs when performing a
+lvalue-to-rvalue conversion on an object lvalue.
+
+<ul>
+<li>For <tt>__weak</tt> 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.</li>
+<li>For all other objects, the lvalue is loaded with primitive
+semantics.</li>
+</ul>
+</p>
+
+<p><span class="term">Assignment</span> occurs when evaluating
+an assignment operator. The semantics vary based on the qualification:
+<ul>
+<li>For <tt>__strong</tt> 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.</li>
+<li>For <tt>__weak</tt> 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.</li>
+<li>For <tt>__unsafe_unretained</tt> objects, the new pointee is
+stored into the lvalue using primitive semantics.</li>
+<li>For <tt>__autoreleasing</tt> objects, the new pointee is retained,
+autoreleased, and stored into the lvalue using primitive semantics.</li>
+</ul>
+</p>
+
+<p><span class="term">Initialization</span> occurs when an object's
+lifetime begins, which depends on its storage duration.
+Initialization proceeds in two stages:
+<ol>
+<li>First, a null pointer is stored into the lvalue using primitive
+semantics. This step is skipped if the object
+is <tt>__unsafe_unretained</tt>.</li>
+<li>Second, if the object has an initializer, that expression is
+evaluated and then assigned into the object using the usual assignment
+semantics.</li>
+</ol>
+</p>
+
+<p><span class="term">Destruction</span> 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.</p>
+
+<p><span class="term">Moving</span> occurs in specific situations
+where an lvalue is <q>moved from</q>, meaning that its current pointee
+will be used but the object may be left in a different (but still
+valid) state. This arises with <tt>__block</tt> variables and rvalue
+references in C++. For <tt>__strong</tt> 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.</p>
+
+</div> <!-- ownership.semantics -->
+
+<div id="ownership.restrictions">
+<h1>Restrictions</h1>
+
+<div id="ownership.restrictions.weak">
+<h1>Weak-unavailable types</h1>
+
+<p>It is explicitly permitted for Objective-C classes to not
+support <tt>__weak</tt> 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 <tt>__weak</tt>
+references.</p>
+
+<div class="rationale"><p>Rationale: historically, it has been
+possible for a class to provide its own reference-count implementation
+by overriding <tt>retain</tt>, <tt>release</tt>, 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.</p></div>
+
+<p>A class may indicate that it does not support weak references by
+providing the <tt>objc_arc_weak_unavailable</tt> attribute on the
+class's interface declaration. A retainable object pointer type
+is <span class="term">weak-unavailable</span> if is a pointer to an
+(optionally protocol-qualified) Objective-C class <tt>T</tt>
+where <tt>T</tt> or one of its superclasses has
+the <tt>objc_arc_weak_unavailable</tt> attribute. A program is
+ill-formed if it applies the <tt>__weak</tt> ownership qualifier to a
+weak-unavailable type or if the value operand of a weak assignment
+operation has a weak-unavailable type.</p>
+</div> <!-- ownership.restrictions.weak -->
+
+<div id="ownership.restrictions.autoreleasing">
+<h1>Storage duration of <tt>__autoreleasing</tt> objects</h1>
+
+<p>A program is ill-formed if it declares an <tt>__autoreleasing</tt>
+object of non-automatic storage duration.</p>
+
+<div class="rationale"><p>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.</p></div>
+
+<p>It is undefined behavior if a non-null pointer is assigned to
+an <tt>__autoreleasing</tt> object while an autorelease pool is in
+scope and then that object is read after the autorelease pool's scope
+is left.</p>
+
+</div>
+
+<div id="ownership.restrictions.conversion.indirect">
+<h1>Conversion of pointers to ownership-qualified types</h1>
+
+<p>A program is ill-formed if an expression of type <tt>T*</tt> is
+converted, explicitly or implicitly, to the type <tt>U*</tt>,
+where <tt>T</tt> and <tt>U</tt> have different ownership
+qualification, unless:
+<ul>
+<li><tt>T</tt> is qualified with <tt>__strong</tt>,
+ <tt>__autoreleasing</tt>, or <tt>__unsafe_unretained</tt>, and
+ <tt>U</tt> is qualified with both <tt>const</tt> and
+ <tt>__unsafe_unretained</tt>; or</li>
+<li>either <tt>T</tt> or <tt>U</tt> is <tt>cv void</tt>, where
+<tt>cv</tt> is an optional sequence of non-ownership qualifiers; or</li>
+<li>the conversion is requested with a <tt>reinterpret_cast</tt> in
+ Objective-C++; or</li>
+<li>the conversion is a
+well-formed <a href="#ownership.restrictions.pass_by_writeback">pass-by-writeback</a>.</li>
+</ul>
+</p>
+
+<p>The analogous rule applies to <tt>T&</tt> and <tt>U&</tt> in
+Objective-C++.</p>
+
+<div class="rationale"><p>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 <tt>const
+__unsafe_unretained</tt> 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 <tt>void*</tt> is
+useful for allocating memory or otherwise escaping the type system,
+but use it carefully. <tt>reinterpret_cast</tt> is considered to be
+an obvious enough sign of taking responsibility for any
+problems.</p></div>
+
+<p>It is undefined behavior to access an ownership-qualified object
+through an lvalue of a differently-qualified type, except that any
+non-<tt>__weak</tt> object may be read through
+an <tt>__unsafe_unretained</tt> lvalue.</p>
+
+<p>It is undefined behavior if a managed operation is performed on
+a <tt>__strong</tt> or <tt>__weak</tt> 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.</p>
+
+<div class="rationale"><p>Rationale: ARC cannot differentiate between
+an assignment operator which is intended to <q>initialize</q> 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 (<tt>__strong</tt> objects) and
+consistency errors (<tt>__weak</tt> objects).</p>
+
+<p>These requirements are followed automatically in Objective-C++ when
+creating objects of retainable object owner type with <tt>new</tt>
+or <tt>new[]</tt> and destroying them with <tt>delete</tt>,
+<tt>delete[]</tt>, 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 <tt>new[]</tt>'d in ARC translation units cannot
+be <tt>delete[]</tt>'d in non-ARC translation units and
+vice-versa.</p></div>
+
+</div>
+
+<div id="ownership.restrictions.pass_by_writeback">
+<h1>Passing to an out parameter by writeback</h1>
+
+<p>If the argument passed to a parameter of type
+<tt>T __autoreleasing *</tt> has type <tt>U oq *</tt>,
+where <tt>oq</tt> is an ownership qualifier, then the argument is a
+candidate for <span class="term">pass-by-writeback</span> if:</p>
+
+<ul>
+<li><tt>oq</tt> is <tt>__strong</tt> or <tt>__weak</tt>, and
+<li>it would be legal to initialize a <tt>T __strong *</tt> with
+a <tt>U __strong *</tt>.</li>
+</ul>
+
+<p>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.</p>
+
+<p>The pass-by-writeback is ill-formed if the argument expression does
+not have a legal form:</p>
+
+<ul>
+<li><tt>&var</tt>, where <tt>var</tt> is a scalar variable of
+automatic storage duration with retainable object pointer type</li>
+<li>a conditional expression where the second and third operands are
+both legal forms</li>
+<li>a cast whose operand is a legal form</li>
+<li>a null pointer constant</li>
+</ul>
+
+<div class="rationale"><p>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 <q>array</q>
+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.</p></div>
+
+<p>A pass-by-writeback is evaluated as follows:
+<ol>
+<li>The argument is evaluated to yield a pointer <tt>p</tt> of
+ type <tt>U oq *</tt>.</li>
+<li>If <tt>p</tt> is a null pointer, then a null pointer is passed as
+ the argument, and no further work is required for the pass-by-writeback.</li>
+<li>Otherwise, a temporary of type <tt>T __autoreleasing</tt> is
+ created and initialized to a null pointer.</li>
+<li>If the argument is not an Objective-C method parameter marked
+ <tt>out</tt>, then <tt>*p</tt> is read, and the result is written
+ into the temporary with primitive semantics.</li>
+<li>The address of the temporary is passed as the argument to the
+ actual call.</li>
+<li>After the call completes, the temporary is loaded with primitive
+ semantics, and that value is assigned into <tt>*p</tt>.</li>
+</ol></p>
+
+<div class="rationale"><p>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 <tt>__autoreleasing</tt> rather than <tt>__strong</tt>. 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 <tt>__autoreleasing</tt> on all the variables
+they intend to use for out-parameters. This was the least bad
+solution.</p></div>
+
+</div>
+
+<div id="ownership.restrictions.records">
+<h1>Ownership-qualified fields of structs and unions</h1>
+
+<p>A program is ill-formed if it declares a member of a C struct or
+union to have a nontrivially ownership-qualified type.</p>
+
+<div class="rationale"><p>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 <tt>void*</tt> or an <tt>__unsafe_unretained</tt>
+object.</p></div>
+
+<p>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.</p>
+
+<div class="rationale"><p>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.</p></div>
+
+</div>
+
+</div>
+
+<div id="ownership.inference">
+<h1>Ownership inference</h1>
+
+<div id="ownership.inference.variables">
+<h1>Objects</h1>
+
+<p>If an object is declared with retainable object owner type, but
+without an explicit ownership qualifier, its type is implicitly
+adjusted to have <tt>__strong</tt> qualification.</p>
+
+<p>As a special case, if the object's base type is <tt>Class</tt>
+(possibly protocol-qualified), the type is adjusted to
+have <tt>__unsafe_unretained</tt> qualification instead.</p>
+
+</div>
+
+<div id="ownership.inference.indirect_parameters">
+<h1>Indirect parameters</h1>
+
+<p>If a function or method parameter has type <tt>T*</tt>, where
+<tt>T</tt> is an ownership-unqualified retainable object pointer type,
+then:</p>
+
+<ul>
+<li>if <tt>T</tt> is <tt>const</tt>-qualified or <tt>Class</tt>, then
+it is implicitly qualified with <tt>__unsafe_unretained</tt>;</li>
+<li>otherwise, it is implicitly qualified
+with <tt>__autoreleasing</tt>.</li>
+</ul>
+</p>
+
+<div class="rationale"><p>Rationale: <tt>__autoreleasing</tt> exists
+mostly for this case, the Cocoa convention for out-parameters. Since
+a pointer to <tt>const</tt> 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 <em>mutable</em> array, inferring
+<tt>__autoreleasing</tt> is the wrong thing to do; this directs some
+of the caution in the following rules about writeback.</p></div>
+
+<p>Such a type written anywhere else would be ill-formed by the
+general rule requiring ownership qualifiers.</p>
+
+<p>This rule does not apply in Objective-C++ if a parameter's type is
+dependent in a template pattern and is only <em>instantiated</em> to
+a type which would be a pointer to an unqualified retainable object
+pointer type. Such code is still ill-formed.</p>
+
+<div class="rationale"><p>Rationale: the convention is very unlikely
+to be intentional in template code.</p></div>
+
+</div> <!-- ownership.inference.indirect_parameters -->
+
+<div id="ownership.inference.template_arguments">
+<h1>Template arguments</h1>
+
+<p>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 <tt>__strong</tt>
+qualification. This adjustment occurs regardless of whether the
+template argument was deduced or explicitly specified. </p>
+
+<div class="rationale"><p>Rationale: <tt>__strong</tt> is a useful default for containers (e.g., <tt>std::vector&lt;id&gt;</tt>), 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.</p></div>
+
+</div> <!-- ownership.inference.template_arguments -->
+</div> <!-- ownership.inference -->
+</div> <!-- ownership -->
+
+
+<div id="family">
+<h1>Method families</h1>
+
+<p>An Objective-C method may fall into a <span class="term">method
+family</span>, which is a conventional set of behaviors ascribed to it
+by the Cocoa conventions.</p>
+
+<p>A method is in a certain method family if:
+<ul>
+<li>it has a <tt>objc_method_family</tt> attribute placing it in that
+ family; or if not that,</li>
+<li>it does not have an <tt>objc_method_family</tt> attribute placing
+ it in a different or no family, and</li>
+<li>its selector falls into the corresponding selector family, and</li>
+<li>its signature obeys the added restrictions of the method family.</li>
+</ul></p>
+
+<p>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, <tt>_perform:with:</tt> and <tt>performWith:</tt> would fall
+into the <tt>perform</tt> family (if we recognized one),
+but <tt>performing:with</tt> would not.</p>
+
+<p>The families and their added restrictions are:</p>
+
+<ul>
+<li><tt>alloc</tt> methods must return a retainable object pointer type.</li>
+<li><tt>copy</tt> methods must return a retainable object pointer type.</li>
+<li><tt>mutableCopy</tt> methods must return a retainable object pointer type.</li>
+<li><tt>new</tt> methods must return a retainable object pointer type.</li>
+<li><tt>init</tt> 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 <tt>init</tt> method whose return
+type is neither <tt>id</tt> 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).</p>
+
+<div class="rationale"><p>Rationale: there are a fair number of existing
+methods with <tt>init</tt>-like selectors which nonetheless don't
+follow the <tt>init</tt> conventions. Typically these are either
+accidental naming collisions or helper methods called during
+initialization. Because of the peculiar retain/release behavior
+of <tt>init</tt> methods, it's very important not to treat these
+methods as <tt>init</tt> 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 <tt>init</tt> family.</p>
+
+<p>Note that a method with an <tt>init</tt>-family selector which
+returns a non-Objective-C type (e.g. <tt>void</tt>) is perfectly
+well-formed; it simply isn't in the <tt>init</tt> family.</p></div>
+</li>
+</ul>
+
+<p>A program is ill-formed if a method's declarations,
+implementations, and overrides do not all have the same method
+family.</p>
+
+<div id="family.attribute">
+<h1>Explicit method family control</h1>
+
+<p>A method may be annotated with the <tt>objc_method_family</tt>
+attribute to precisely control which method family it belongs to. If
+a method in an <tt>@implementation</tt> does not have this attribute,
+but there is a method declared in the corresponding <tt>@interface</tt>
+that does, then the attribute is copied to the declaration in the
+<tt>@implementation</tt>. The attribute is available outside of ARC,
+and may be tested for with the preprocessor query
+<tt>__has_attribute(objc_method_family)</tt>.</p>
+
+<p>The attribute is spelled
+<tt>__attribute__((objc_method_family(<i>family</i>)))</tt>.
+If <i>family</i> is <tt>none</tt>, the method has no family, even if
+it would otherwise be considered to have one based on its selector and
+type. Otherwise, <i>family</i> must be one
+of <tt>alloc</tt>, <tt>copy</tt>, <tt>init</tt>,
+<tt>mutableCopy</tt>, or <tt>new</tt>, 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.</p>
+
+<div class="rationale"><p>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
+<tt>ns_returns_retained</tt>, this attribute allows the user to
+communicate semantic intent, which of use both to ARC (which, e.g.,
+treats calls to <tt>init</tt> specially) and the static analyzer.</p></div>
+</div>
+
+<div id="family.semantics">
+<h1>Semantics of method families</h1>
+
+<p>A method's membership in a method family may imply non-standard
+semantics for its parameters and return type.</p>
+
+<p>Methods in the <tt>alloc</tt>, <tt>copy</tt>, <tt>mutableCopy</tt>,
+and <tt>new</tt> families &mdash; that is, methods in all the
+currently-defined families except <tt>init</tt> &mdash; implicitly
+<a href="#objects.operands.retained_returns">return a retained
+object</a> as if they were annotated with
+the <tt>ns_returns_retained</tt> attribute. This can be overridden by
+annotating the method with either of
+the <tt>ns_returns_autoreleased</tt> or
+<tt>ns_returns_not_retained</tt> attributes.</p>
+
+<p>Properties also follow same naming rules as methods. This means that
+those in the <tt>alloc</tt>, <tt>copy</tt>, <tt>mutableCopy</tt>,
+and <tt>new</tt> families provide access to
+<a href="#objects.operands.retained_returns">retained objects</a>.
+This can be overridden by annotating the property with
+<tt>ns_returns_not_retained</tt> attribute.</p>
+
+<div id="family.semantics.init">
+<h1>Semantics of <tt>init</tt></h1>
+<p>Methods in the <tt>init</tt> family implicitly
+<a href="#objects.operands.consumed">consume</a> their <tt>self</tt>
+parameter and <a href="#objects.operands.retained_returns">return a
+retained object</a>. Neither of these properties can be altered
+through attributes.</p>
+
+<p>A call to an <tt>init</tt> method with a receiver that is either
+<tt>self</tt> (possibly parenthesized or casted) or <tt>super</tt> is
+called a <span class="term">delegate init call</span>. It is an error
+for a delegate init call to be made except from an <tt>init</tt>
+method, and excluding blocks within such methods.</p>
+
+<p>As an exception to the <a href="misc.self">usual rule</a>, the
+variable <tt>self</tt> is mutable in an <tt>init</tt> method and has
+the usual semantics for a <tt>__strong</tt> variable. However, it is
+undefined behavior and the program is ill-formed, no diagnostic
+required, if an <tt>init</tt> method attempts to use the previous
+value of <tt>self</tt> after the completion of a delegate init call.
+It is conventional, but not required, for an <tt>init</tt> method to
+return <tt>self</tt>.</p>
+
+<p>It is undefined behavior for a program to cause two or more calls
+to <tt>init</tt> methods on the same object, except that
+each <tt>init</tt> method invocation may perform at most one delegate
+init call.</p>
+
+</div> <!-- family.semantics.init -->
+
+<div id="family.semantics.result_type">
+<h1>Related result types</h1>
+
+<p>Certain methods are candidates to have <span class="term">related
+result types</span>:</p>
+<ul>
+<li>class methods in the <tt>alloc</tt> and <tt>new</tt> method families</li>
+<li>instance methods in the <tt>init</tt> family</li>
+<li>the instance method <tt>self</tt></li>
+<li>outside of ARC, the instance methods <tt>retain</tt> and <tt>autorelease</tt></li>
+</ul>
+
+<p>If the formal result type of such a method is <tt>id</tt> or
+protocol-qualified <tt>id</tt>, 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:</p>
+
+<ul>
+<li>if it is a class method, and the receiver is a class
+name <tt>T</tt>, the message send expression has type <tt>T*</tt>;
+otherwise</li>
+<li>if it is an instance method, and the receiver has type <tt>T</tt>,
+the message send expression has type <tt>T</tt>; otherwise</li>
+<li>the message send expression has the normal result type of the
+method.</li>
+</ul>
+
+<p>This is a new rule of the Objective-C language and applies outside
+of ARC.</p>
+
+<div class="rationale"><p>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.</p></div>
+
+</div> <!-- family.semantics.result_type -->
+</div> <!-- family.semantics -->
+</div> <!-- family -->
+
+<div id="optimization">
+<h1>Optimization</h1>
+
+<p>ARC applies aggressive rules for the optimization of local
+behavior. These rules are based around a core assumption of
+<span class="term">local balancing</span>: 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 <q>balancing</q> retains, such that
+the local retain/release pair is the only thing preventing the called
+function from ending up with a dangling reference.</p>
+
+<p>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.</p>
+
+<p>The complete optimization rules are quite complicated, but it would
+still be useful to document them here.</p>
+
+</div>
+
+<div id="misc">
+<h1>Miscellaneous</h1>
+
+<div id="misc.special_methods">
+<h1>Special methods</h1>
+
+<div id="misc.special_methods.retain">
+<h1>Memory management methods</h1>
+
+<p>A program is ill-formed if it contains a method definition, message
+send, or <tt>@selector</tt> expression for any of the following
+selectors:
+<ul>
+<li><tt>autorelease</tt></li>
+<li><tt>release</tt></li>
+<li><tt>retain</tt></li>
+<li><tt>retainCount</tt></li>
+</ul>
+</p>
+
+<div class="rationale"><p>Rationale: <tt>retainCount</tt> is banned
+because ARC robs it of consistent semantics. The others were banned
+after weighing three options for how to deal with message sends:</p>
+
+<p><b>Honoring</b> 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 <q>unrooted</q>
+retains, i.e. retains not logically corresponding to a strong
+reference in the object graph.</p>
+
+<p><b>Ignoring</b> them would badly violate user expectations about their
+code. While it <em>would</em> 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.</p>
+
+<p><b>Banning</b> 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.</p>
+
+<p>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 <a href="#objects.retains">semantics</a>
+laid out elsewhere in this document.</p>
+
+</div>
+</div> <!-- misc.special_methods.retain -->
+
+<div id="misc.special_methods.dealloc">
+<h1><tt>dealloc</tt></h1>
+
+<p>A program is ill-formed if it contains a message send
+or <tt>@selector</tt> expression for the selector <tt>dealloc</tt>.</p>
+
+<div class="rationale"><p>Rationale: there are no legitimate reasons
+to call <tt>dealloc</tt> directly.</p></div>
+
+<p>A class may provide a method definition for an instance method
+named <tt>dealloc</tt>. This method will be called after the final
+<tt>release</tt> of the object but before it is deallocated or any of
+its instance variables are destroyed. The superclass's implementation
+of <tt>dealloc</tt> will be called automatically when the method
+returns.</p>
+
+<div class="rationale"><p>Rationale: even though ARC destroys instance
+variables automatically, there are still legitimate reasons to write
+a <tt>dealloc</tt> method, such as freeing non-retainable resources.
+Failing to call <tt>[super&nbsp;dealloc]</tt> in such a method is nearly
+always a bug. Sometimes, the object is simply trying to prevent
+itself from being destroyed, but <tt>dealloc</tt> 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 <tt>free</tt>; for now, this can only be supported
+with a <tt>dealloc</tt> implementation outside of ARC. Such an
+implementation must be very careful to do all the other work
+that <tt>NSObject</tt>'s <tt>dealloc</tt> would, which is outside the
+scope of this document to describe.</p></div>
+
+</div>
+
+</div> <!-- misc.special_methods -->
+
+<div id="autoreleasepool">
+<h1><tt>@autoreleasepool</tt></h1>
+
+<p>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 <tt>@autoreleasepool</tt> followed by
+a <i>compound-statement</i>, 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 <tt>return</tt> or <tt>break</tt>), 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.</p>
+
+<p><tt>@autoreleasepool</tt> may be used in non-ARC translation units,
+with equivalent semantics.</p>
+
+<p>A program is ill-formed if it refers to the
+<tt>NSAutoreleasePool</tt> class.</p>
+
+<div class="rationale"><p>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.</p></div>
+
+</div> <!-- autoreleasepool -->
+
+<div id="misc.self">
+<h1><tt>self</tt></h1>
+
+<p>The <tt>self</tt> 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, <tt>self</tt> is implicitly <tt>const</tt> unless the method is
+in the <a href="#family.semantics.init"><tt>init</tt> family</a>.</p>
+
+<div class="rationale"><p>Rationale: the cost of
+retaining <tt>self</tt> 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 &mdash; 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 <tt>__unsafe_unretained</tt>), we chose to
+make this optimizing assumption and shift some amount of risk to the
+user.</p></div>
+
+</div> <!-- misc.self -->
+
+<div id="misc.enumeration">
+<h1>Fast enumeration iteration variables</h1>
+
+<p>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 <tt>const __strong</tt> and
+objects encountered during the enumeration are not actually
+retained.</p>
+
+<div class="rationale"><p>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 <tt>__strong</tt>, which will make the variable
+mutable again and cause the loop to retain the objects it
+encounters.</div>
+
+</div>
+
+<div id="misc.blocks">
+<h1>Blocks</h1>
+
+<p>The implicit <tt>const</tt> 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.</p>
+
+<p>The <a href="#ownership.inference">inference</a> rules apply
+equally to <tt>__block</tt> variables, which is a shift in semantics
+from non-ARC, where <tt>__block</tt> variables did not implicitly
+retain during capture.</p>
+
+<p><tt>__block</tt> 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.</tt></p>
+
+<p>With the exception of retains done as part of initializing
+a <tt>__strong</tt> parameter variable or reading a <tt>__weak</tt>
+variable, whenever these semantics call for retaining a value of
+block-pointer type, it has the effect of a <tt>Block_copy</tt>. The
+optimizer may remove such copies when it sees that the result is
+used only as an argument to a call.</p>
+
+</div> <!-- misc.blocks -->
+
+<div id="misc.exceptions">
+<h1>Exceptions</h1>
+
+<p>By default in Objective C, ARC is not exception-safe for normal
+releases:
+<ul>
+<li>It does not end the lifetime of <tt>__strong</tt> variables when
+their scopes are abnormally terminated by an exception.</li>
+<li>It does not perform releases which would occur at the end of
+a full-expression if that full-expression throws an exception.</li>
+</ul>
+
+<p>A program may be compiled with the option
+<tt>-fobjc-arc-exceptions</tt> in order to enable these, or with the
+option <tt>-fno-objc-arc-exceptions</tt> to explicitly disable them,
+with the last such argument <q>winning</q>.</p>
+
+<div class="rationale"><p>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.</p></div>
+
+<p>In Objective-C++, <tt>-fobjc-arc-exceptions</tt> is enabled by
+default.</p>
+
+<div class="rationale"><p>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.</p></div>
+
+<p>ARC does end the lifetimes of <tt>__weak</tt> objects when an
+exception terminates their scope unless exceptions are disabled in the
+compiler.</p>
+
+<div class="rationale"><p>Rationale: the consequence of a
+local <tt>__weak</tt> 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.</p></div>
+
+</div> <!-- misc.exceptions -->
+
+</div> <!-- misc -->
+
+<div id="runtime">
+<h1>Runtime support</h1>
+
+<p>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 <q>Itanium</q> generic ABI for C++.</p>
+
+<p>Ownership qualification does not alter the storage requirements for
+objects, except that it is undefined behavior if a <tt>__weak</tt>
+object is inadequately aligned for an object of type <tt>id</tt>. The
+other qualifiers may be used on explicitly under-aligned memory.</p>
+
+<p>The runtime tracks <tt>__weak</tt> objects which holds non-null
+values. It is undefined behavior to direct modify a <tt>__weak</tt>
+object which is being tracked by the runtime except through an
+<a href="#runtime.objc_storeWeak"><tt>objc_storeWeak</tt></a>,
+<a href="#runtime.objc_destroyWeak"><tt>objc_destroyWeak</tt></a>,
+or <a href="#runtime.objc_moveWeak"><tt>objc_moveWeak</tt></a>
+call.</p>
+
+<p>The runtime must provide a number of new entrypoints which the
+compiler may emit, which are described in the remainder of this
+section.</p>
+
+<div class="rationale"><p>Rationale: Several of these functions are
+semantically equivalent to a message send; we emit calls to C
+functions instead because:</p>
+<ul>
+<li>the machine code to do so is significantly smaller,</li>
+<li>it is much easier to recognize the C functions in the ARC optimizer, and</li>
+<li>a sufficient sophisticated runtime may be able to avoid the
+message send in common cases.</li>
+</ul>
+
+<p>Several other of these functions are <q>fused</q> 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.</p>
+
+</div>
+
+<div id="runtime.objc_autorelease">
+<h1><tt>id objc_autorelease(id value);</tt></h1>
+<p><i>Precondition:</i> <tt>value</tt> is null or a pointer to a
+valid object.</p>
+<p>If <tt>value</tt> 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 <tt>autorelease</tt> message.</p>
+<p>Always returns <tt>value</tt>.</p>
+</div> <!-- runtime.objc_autorelease -->
+
+<div id="runtime.objc_autoreleasePoolPop">
+<h1><tt>void objc_autoreleasePoolPop(void *pool);</tt></h1>
+<p><i>Precondition:</i> <tt>pool</tt> is the result of a previous call to
+<a href="runtime.objc_autoreleasePoolPush"><tt>objc_autoreleasePoolPush</tt></a>
+on the current thread, where neither <tt>pool</tt> nor any enclosing
+pool have previously been popped.</p>
+<p>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 <tt>pool</tt>.</p>
+</div> <!-- runtime.objc_autoreleasePoolPop -->
+
+<div id="runtime.objc_autoreleasePoolPush">
+<h1><tt>void *objc_autoreleasePoolPush(void);</tt></h1>
+<p>Creates a new autorelease pool that is enclosed by the current
+pool, makes that the current pool, and returns an opaque <q>handle</q>
+to it.</p>
+
+<div class="rationale"><p>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.</p></div>
+
+</div> <!-- runtime.objc_autoreleasePoolPush -->
+
+<div id="runtime.objc_autoreleaseReturnValue">
+<h1><tt>id objc_autoreleaseReturnValue(id value);</tt></h1>
+<p><i>Precondition:</i> <tt>value</tt> is null or a pointer to a
+valid object.</p>
+<p>If <tt>value</tt> 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 <a href="runtime.objc_retainAutoreleasedReturnValue"><tt>objc_retainAutoreleasedReturnValue</tt></a>
+for the same object in an enclosing call frame. If this is not
+possible, the object is autoreleased as above.</p>
+<p>Always returns <tt>value</tt>.</p>
+</div> <!-- runtime.objc_autoreleaseReturnValue -->
+
+<div id="runtime.objc_copyWeak">
+<h1><tt>void objc_copyWeak(id *dest, id *src);</tt></h1>
+<p><i>Precondition:</i> <tt>src</tt> is a valid pointer which either
+contains a null pointer or has been registered as a <tt>__weak</tt>
+object. <tt>dest</tt> is a valid pointer which has not been
+registered as a <tt>__weak</tt> object.</p>
+<p><tt>dest</tt> is initialized to be equivalent to <tt>src</tt>,
+potentially registering it with the runtime. Equivalent to the
+following code:</p>
+<pre>void objc_copyWeak(id *dest, id *src) {
+ objc_release(objc_initWeak(dest, objc_loadWeakRetained(src)));
+}</pre>
+<p>Must be atomic with respect to calls to <tt>objc_storeWeak</tt>
+on <tt>src</tt>.</p>
+</div> <!-- runtime.objc_copyWeak -->
+
+<div id="runtime.objc_destroyWeak">
+<h1><tt>void objc_destroyWeak(id *object);</tt></h1>
+<p><i>Precondition:</i> <tt>object</tt> is a valid pointer which
+either contains a null pointer or has been registered as
+a <tt>__weak</tt> object.</p>
+<p><tt>object</tt> is unregistered as a weak object, if it ever was.
+The current value of <tt>object</tt> is left unspecified; otherwise,
+equivalent to the following code:</p>
+<pre>void objc_destroyWeak(id *object) {
+ objc_storeWeak(object, nil);
+}</pre>
+<p>Does not need to be atomic with respect to calls
+to <tt>objc_storeWeak</tt> on <tt>object</tt>.</p>
+</div> <!-- runtime.objc_destroyWeak -->
+
+<div id="runtime.objc_initWeak">
+<h1><tt>id objc_initWeak(id *object, id value);</tt></h1>
+<p><i>Precondition:</i> <tt>object</tt> is a valid pointer which has
+not been registered as a <tt>__weak</tt> object. <tt>value</tt> is
+null or a pointer to a valid object.</p>
+<p>If <tt>value</tt> is a null pointer or the object to which it
+points has begun deallocation, <tt>object</tt> is zero-initialized.
+Otherwise, <tt>object</tt> is registered as a <tt>__weak</tt> object
+pointing to <tt>value</tt>. Equivalent to the following code:</p>
+<pre>id objc_initWeak(id *object, id value) {
+ *object = nil;
+ return objc_storeWeak(object, value);
+}</pre>
+<p>Returns the value of <tt>object</tt> after the call.</p>
+<p>Does not need to be atomic with respect to calls
+to <tt>objc_storeWeak</tt> on <tt>object</tt>.</p>
+</div> <!-- runtime.objc_initWeak -->
+
+<div id="runtime.objc_loadWeak">
+<h1><tt>id objc_loadWeak(id *object);</tt></h1>
+<p><i>Precondition:</i> <tt>object</tt> is a valid pointer which
+either contains a null pointer or has been registered as
+a <tt>__weak</tt> object.</p>
+<p>If <tt>object</tt> is registered as a <tt>__weak</tt> object, and
+the last value stored into <tt>object</tt> has not yet been
+deallocated or begun deallocation, retains and autoreleases that value
+and returns it. Otherwise returns null. Equivalent to the following
+code:</p>
+<pre>id objc_loadWeak(id *object) {
+ return objc_autorelease(objc_loadWeakRetained(object));
+}</pre>
+<p>Must be atomic with respect to calls to <tt>objc_storeWeak</tt>
+on <tt>object</tt>.</p>
+<div class="rationale">Rationale: loading weak references would be
+inherently prone to race conditions without the retain.</div>
+</div> <!-- runtime.objc_loadWeak -->
+
+<div id="runtime.objc_loadWeakRetained">
+<h1><tt>id objc_loadWeakRetained(id *object);</tt></h1>
+<p><i>Precondition:</i> <tt>object</tt> is a valid pointer which
+either contains a null pointer or has been registered as
+a <tt>__weak</tt> object.</p>
+<p>If <tt>object</tt> is registered as a <tt>__weak</tt> object, and
+the last value stored into <tt>object</tt> has not yet been
+deallocated or begun deallocation, retains that value and returns it.
+Otherwise returns null.</p>
+<p>Must be atomic with respect to calls to <tt>objc_storeWeak</tt>
+on <tt>object</tt>.</p>
+</div> <!-- runtime.objc_loadWeakRetained -->
+
+<div id="runtime.objc_moveWeak">
+<h1><tt>void objc_moveWeak(id *dest, id *src);</tt></h1>
+<p><i>Precondition:</i> <tt>src</tt> is a valid pointer which either
+contains a null pointer or has been registered as a <tt>__weak</tt>
+object. <tt>dest</tt> is a valid pointer which has not been
+registered as a <tt>__weak</tt> object.</p>
+<p><tt>dest</tt> is initialized to be equivalent to <tt>src</tt>,
+potentially registering it with the runtime. <tt>src</tt> may then be
+left in its original state, in which case this call is equivalent
+to <a href="#runtime.objc_copyWeak"><tt>objc_copyWeak</tt></a>, or it
+may be left as null.</p>
+<p>Must be atomic with respect to calls to <tt>objc_storeWeak</tt>
+on <tt>src</tt>.</p>
+</div> <!-- runtime.objc_moveWeak -->
+
+<div id="runtime.objc_release">
+<h1><tt>void objc_release(id value);</tt></h1>
+<p><i>Precondition:</i> <tt>value</tt> is null or a pointer to a
+valid object.</p>
+<p>If <tt>value</tt> is null, this call has no effect. Otherwise, it
+performs a release operation exactly as if the object had been sent
+the <tt>release</tt> message.</p>
+</div> <!-- runtime.objc_release -->
+
+<div id="runtime.objc_retain">
+<h1><tt>id objc_retain(id value);</tt></h1>
+<p><i>Precondition:</i> <tt>value</tt> is null or a pointer to a
+valid object.</p>
+<p>If <tt>value</tt> is null, this call has no effect. Otherwise, it
+performs a retain operation exactly as if the object had been sent
+the <tt>retain</tt> message.</p>
+<p>Always returns <tt>value</tt>.</p>
+</div> <!-- runtime.objc_retain -->
+
+<div id="runtime.objc_retainAutorelease">
+<h1><tt>id objc_retainAutorelease(id value);</tt></h1>
+<p><i>Precondition:</i> <tt>value</tt> is null or a pointer to a
+valid object.</p>
+<p>If <tt>value</tt> is null, this call has no effect. Otherwise, it
+performs a retain operation followed by an autorelease operation.
+Equivalent to the following code:</p>
+<pre>id objc_retainAutorelease(id value) {
+ return objc_autorelease(objc_retain(value));
+}</pre>
+<p>Always returns <tt>value</tt>.</p>
+</div> <!-- runtime.objc_retainAutorelease -->
+
+<div id="runtime.objc_retainAutoreleaseReturnValue">
+<h1><tt>id objc_retainAutoreleaseReturnValue(id value);</tt></h1>
+<p><i>Precondition:</i> <tt>value</tt> is null or a pointer to a
+valid object.</p>
+<p>If <tt>value</tt> is null, this call has no effect. Otherwise, it
+performs a retain operation followed by the operation described in
+<a href="#runtime.objc_autoreleaseReturnValue"><tt>objc_autoreleaseReturnValue</tt></a>.
+Equivalent to the following code:</p>
+<pre>id objc_retainAutoreleaseReturnValue(id value) {
+ return objc_autoreleaseReturnValue(objc_retain(value));
+}</pre>
+<p>Always returns <tt>value</tt>.</p>
+</div> <!-- runtime.objc_retainAutoreleaseReturnValue -->
+
+<div id="runtime.objc_retainAutoreleasedReturnValue">
+<h1><tt>id objc_retainAutoreleasedReturnValue(id value);</tt></h1>
+<p><i>Precondition:</i> <tt>value</tt> is null or a pointer to a
+valid object.</p>
+<p>If <tt>value</tt> is null, this call has no effect. Otherwise, it
+attempts to accept a hand off of a retain count from a call to
+<a href="#runtime.objc_autoreleaseReturnValue"><tt>objc_autoreleaseReturnValue</tt></a>
+on <tt>value</tt> in a recently-called function or something it
+calls. If that fails, it performs a retain operation exactly
+like <a href="#runtime.objc_retain"><tt>objc_retain</tt></a>.</p>
+<p>Always returns <tt>value</tt>.</p>
+</div> <!-- runtime.objc_retainAutoreleasedReturnValue -->
+
+<div id="runtime.objc_retainBlock">
+<h1><tt>id objc_retainBlock(id value);</tt></h1>
+<p><i>Precondition:</i> <tt>value</tt> is null or a pointer to a
+valid block object.</p>
+<p>If <tt>value</tt> is null, this call has no effect. Otherwise, if
+the block pointed to by <tt>value</tt> 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 <tt>retain</tt> message.</p>
+</div> <!-- runtime.objc_retainBlock -->
+
+<div id="runtime.objc_storeStrong">
+<h1><tt>id objc_storeStrong(id *object, id value);</tt></h1>
+<p><i>Precondition:</i> <tt>object</tt> is a valid pointer to
+a <tt>__strong</tt> object which is adequately aligned for a
+pointer. <tt>value</tt> is null or a pointer to a valid object.</p>
+<p>Performs the complete sequence for assigning to a <tt>__strong</tt>
+object of non-block type. Equivalent to the following code:</p>
+<pre>id objc_storeStrong(id *object, id value) {
+ value = [value retain];
+ id oldValue = *object;
+ *object = value;
+ [oldValue release];
+ return value;
+}</pre>
+<p>Always returns <tt>value</tt>.</p>
+</div> <!-- runtime.objc_storeStrong -->
+
+<div id="runtime.objc_storeWeak">
+<h1><tt>id objc_storeWeak(id *object, id value);</tt></h1>
+<p><i>Precondition:</i> <tt>object</tt> is a valid pointer which
+either contains a null pointer or has been registered as
+a <tt>__weak</tt> object. <tt>value</tt> is null or a pointer to a
+valid object.</p>
+<p>If <tt>value</tt> is a null pointer or the object to which it
+points has begun deallocation, <tt>object</tt> is assigned null
+and unregistered as a <tt>__weak</tt> object. Otherwise,
+<tt>object</tt> is registered as a <tt>__weak</tt> object or has its
+registration updated to point to <tt>value</tt>.</p>
+<p>Returns the value of <tt>object</tt> after the call.</p>
+</div> <!-- runtime.objc_storeWeak -->
+
+</div> <!-- runtime -->
+</div> <!-- root -->
+</body>
+</html>
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).</p>
+ compilation fails).</p>
<h4 id="int_unified_parsing">Unified Parsing &amp; Pipelining</h4>
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 {
<li><a href="#Constants">Constant Folding in the Clang AST</a></li>
</ul>
</li>
-<li><a href="libIndex.html">The Index Library</a></li>
<li><a href="#Howtos">Howto guides</a>
<ul>
<li><a href="#AddingAttributes">How to add an attribute</a></li>
@@ -1213,8 +1212,8 @@ void g();
void g(int);
</pre>
<p>the <code>DeclContext::lookup</code> operation will return
- an <code>OverloadedFunctionDecl</code> that contains both
- declarations of "g". Clients that perform semantic analysis on a
+ a <code>DeclContext::lookup_result</code> 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.</p>
@@ -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 <code>N</code> for
- "f" will return an <code>OverloadedFunctionDecl</code> that contains
- both declarations of "f".</p>
+ "f" will return a <code>DeclContext::lookup_result</code> that contains
+ a range of iterators over declarations of "f".</p>
<p><code>DeclContext</code> 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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
<html>
<head>
-<title>Clang Language Extensions</title>
-<link type="text/css" rel="stylesheet" href="../menu.css" />
-<link type="text/css" rel="stylesheet" href="../content.css" />
-<style type="text/css">
-td {
- vertical-align: top;
-}
-</style>
+ <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Clang LanguageExtensions</title>
+ <link type="text/css" rel="stylesheet" href="../menu.css">
+ <link type="text/css" rel="stylesheet" href="../content.css">
+ <style type="text/css">
+ td {
+ vertical-align: top;
+ }
+ </style>
</head>
<body>
@@ -25,12 +29,12 @@ td {
<li><a href="#vectors">Vectors and Extended Vectors</a></li>
<li><a href="#deprecated">Messages on <tt>deprecated</tt> and <tt>unavailable</tt> attributes</a></li>
<li><a href="#attributes-on-enumerators">Attributes on enumerators</a></li>
-<li><a href="#checking_language_features">Checks for Standard Language Features</a></li>
+<li><a href="#checking_language_features">Checks for Standard Language Features</a>
<ul>
<li><a href="#cxx_exceptions">C++ exceptions</a></li>
<li><a href="#cxx_rtti">C++ RTTI</a></li>
- </ul>
-<li><a href="#checking_upcoming_features">Checks for Upcoming Standard Language Features</a></li>
+ </ul></li>
+<li><a href="#checking_upcoming_features">Checks for Upcoming Standard Language Features</a>
<ul>
<li><a href="#cxx0x">C++0x</a>
<ul>
@@ -39,6 +43,7 @@ td {
<li><a href="#cxx_alias_templates">C++0x alias templates</a></li>
<li><a href="#cxx_attributes">C++0x attributes</a></li>
<li><a href="#cxx_default_function_template_args">C++0x default template arguments in function templates</a></li>
+ <li><a href="#cxx_delegating_constructor">C++0x delegating constructors</a></li>
<li><a href="#cxx_deleted_functions">C++0x deleted functions</a></li>
<li><a href="#cxx_lambdas">C++0x lambdas</a></li>
<li><a href="#cxx_nullptr">C++0x nullptr</a></li>
@@ -53,18 +58,19 @@ td {
<li><a href="#cxx_strong_enums">C++0x strongly-typed enumerations</a></li>
<li><a href="#cxx_trailing_return">C++0x trailing return type</a></li>
<li><a href="#cxx_noexcept">C++0x noexcept specification</a></li>
- </ul>
+ </ul></li>
<li><a href="#c1x">C1X</a>
<ul>
<li><a href="#c_generic_selections">C1X generic selections</a></li>
<li><a href="#c_static_assert">C1X <tt>_Static_assert()</tt></a></li>
- </ul>
- </ul>
+ </ul></li>
+ </ul> </li>
<li><a href="#checking_type_traits">Checks for Type Traits</a></li>
<li><a href="#blocks">Blocks</a></li>
<li><a href="#objc_features">Objective-C Features</a>
<ul>
<li><a href="#objc_instancetype">Related result types</a></li>
+ <li><a href="#objc_arc">Automatic reference counting</a></li>
</ul>
</li>
<li><a href="#overloading-in-c">Function Overloading in C</a></li>
@@ -104,7 +110,7 @@ code without having to resort to something like autoconf or fragile "compiler
version checks".</p>
<!-- ======================================================================= -->
-<h3 id="__has_builtin">__has_builtin</h3>
+<h3><a name="__has_builtin">__has_builtin</a></h3>
<!-- ======================================================================= -->
<p>This function-like macro takes a single identifier argument that is the name
@@ -129,7 +135,7 @@ not. It can be used like this:</p>
<!-- ======================================================================= -->
-<h3 id="__has_feature_extension">__has_feature and __has_extension</h3>
+<h3><a name="__has_feature_extension"> __has_feature and __has_extension</a></h3>
<!-- ======================================================================= -->
<p>These function-like macros take a single identifier argument that is the
@@ -174,7 +180,7 @@ non-standardized features, i.e. features not prefixed <code>c_</code>,
<p>The feature tag is described along with the language feature below.</p>
<!-- ======================================================================= -->
-<h3 id="__has_attribute">__has_attribute</h3>
+<h3><a name="__has_attribute">__has_attribute</a></h3>
<!-- ======================================================================= -->
<p>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.</p>
<!-- ======================================================================= -->
-<h3 id="__has_include">__has_include</h3>
+<h3><a name="__has_include">__has_include</a></h3>
<!-- ======================================================================= -->
<p>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:</p>
<blockquote>
<pre>
// Note the two possible file name string formats.
-#if __has_include("myinclude.h") && __has_include(&lt;stdint.h&gt;)
+#if __has_include("myinclude.h") &amp;&amp; __has_include(&lt;stdint.h&gt;)
# 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) &amp;&amp; __has_include("myinclude.h")
# include "myinclude.h"
#endif
</pre>
@@ -232,7 +238,7 @@ be found using the include paths, or 0 otherwise:</p>
<p>To test for this feature, use #if defined(__has_include).</p>
<!-- ======================================================================= -->
-<h3 id="__has_include_next">__has_include_next</h3>
+<h3><a name="__has_include_next">__has_include_next</a></h3>
<!-- ======================================================================= -->
<p>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:</p>
<blockquote>
<pre>
// Note the two possible file name string formats.
-#if __has_include_next("myinclude.h") && __has_include_next(&lt;stdint.h&gt;)
+#if __has_include_next("myinclude.h") &amp;&amp; __has_include_next(&lt;stdint.h&gt;)
# 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) &amp;&amp; __has_include_next("myinclude.h")
# include_next "myinclude.h"
#endif
</pre>
@@ -410,115 +416,120 @@ noted.</p>
C++0x standard. As a result, all these features are enabled
with the <tt>-std=c++0x</tt> option when compiling C++ code.</p>
-<h4 id="cxx_decltype">C++0x <tt>decltype()</tt></h3>
+<h4 id="cxx_decltype">C++0x <tt>decltype()</tt></h4>
<p>Use <tt>__has_feature(cxx_decltype)</tt> or
<tt>__has_extension(cxx_decltype)</tt> to determine if support for the
<tt>decltype()</tt> specifier is enabled.</p>
-<h4 id="cxx_access_control_sfinae">C++0x SFINAE includes access control</h3>
+<h4 id="cxx_access_control_sfinae">C++0x SFINAE includes access control</h4>
<p>Use <tt>__has_feature(cxx_access_control_sfinae)</tt> or <tt>__has_extension(cxx_access_control_sfinae)</tt> to determine whether access-control errors (e.g., calling a private constructor) are considered to be template argument deduction errors (aka SFINAE errors), per <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1170">C++ DR1170</a>.</p>
-<h4 id="cxx_alias_templates">C++0x alias templates</h3>
+<h4 id="cxx_alias_templates">C++0x alias templates</h4>
<p>Use <tt>__has_feature(cxx_alias_templates)</tt> or
<tt>__has_extension(cxx_alias_templates)</tt> to determine if support for
C++0x's alias declarations and alias templates is enabled.</p>
-<h4 id="cxx_attributes">C++0x attributes</h3>
+<h4 id="cxx_attributes">C++0x attributes</h4>
<p>Use <tt>__has_feature(cxx_attributes)</tt> or
<tt>__has_extension(cxx_attributes)</tt> to determine if support for attribute
parsing with C++0x's square bracket notation is enabled.</p>
-<h4 id="cxx_default_function_template_args">C++0x default template arguments in function templates</h3>
+<h4 id="cxx_default_function_template_args">C++0x default template arguments in function templates</h4>
<p>Use <tt>__has_feature(cxx_default_function_template_args)</tt> or
<tt>__has_extension(cxx_default_function_template_args)</tt> to determine
if support for default template arguments in function templates is enabled.</p>
-<h4 id="cxx_deleted_functions">C++0x deleted functions</tt></h3>
+<h4 id="cxx_delegating_constructors">C++0x delegating constructors</h4>
+
+<p>Use <tt>__has_feature(cxx_delegating_constructors)</tt> to determine if
+support for delegating constructors is enabled.</p>
+
+<h4 id="cxx_deleted_functions">C++0x <tt>delete</tt>d functions</h4>
<p>Use <tt>__has_feature(cxx_deleted_functions)</tt> or
<tt>__has_extension(cxx_deleted_functions)</tt> to determine if support for
deleted function definitions (with <tt>= delete</tt>) is enabled.</p>
-<h4 id="cxx_lambdas">C++0x lambdas</h3>
+<h4 id="cxx_lambdas">C++0x lambdas</h4>
<p>Use <tt>__has_feature(cxx_lambdas)</tt> or
<tt>__has_extension(cxx_lambdas)</tt> to determine if support for lambdas
is enabled. clang does not currently implement this feature.</p>
-<h4 id="cxx_nullptr">C++0x <tt>nullptr</tt></h3>
+<h4 id="cxx_nullptr">C++0x <tt>nullptr</tt></h4>
<p>Use <tt>__has_feature(cxx_nullptr)</tt> or
<tt>__has_extension(cxx_nullptr)</tt> to determine if support for
<tt>nullptr</tt> is enabled.</p>
-<h4 id="cxx_override_control">C++0x <tt>override control</tt></h3>
+<h4 id="cxx_override_control">C++0x <tt>override control</tt></h4>
<p>Use <tt>__has_feature(cxx_override_control)</tt> or
<tt>__has_extension(cxx_override_control)</tt> to determine if support for
the override control keywords is enabled.</p>
-<h4 id="cxx_reference_qualified_functions">C++0x reference-qualified functions</h3>
+<h4 id="cxx_reference_qualified_functions">C++0x reference-qualified functions</h4>
<p>Use <tt>__has_feature(cxx_reference_qualified_functions)</tt> or
<tt>__has_extension(cxx_reference_qualified_functions)</tt> to determine
if support for reference-qualified functions (e.g., member functions with
<code>&amp;</code> or <code>&amp;&amp;</code> applied to <code>*this</code>)
is enabled.</p>
-<h4 id="cxx_range_for">C++0x range-based for loop</tt></h3>
+<h4 id="cxx_range_for">C++0x range-based <tt>for</tt> loop</h4>
<p>Use <tt>__has_feature(cxx_range_for)</tt> or
<tt>__has_extension(cxx_range_for)</tt> to determine if support for the
range-based for loop is enabled. </p>
-<h4 id="cxx_rvalue_references">C++0x rvalue references</tt></h3>
+<h4 id="cxx_rvalue_references">C++0x rvalue references</h4>
<p>Use <tt>__has_feature(cxx_rvalue_references)</tt> or
<tt>__has_extension(cxx_rvalue_references)</tt> to determine if support for
rvalue references is enabled. </p>
-<h4 id="cxx_static_assert">C++0x <tt>static_assert()</tt></h3>
+<h4 id="cxx_static_assert">C++0x <tt>static_assert()</tt></h4>
<p>Use <tt>__has_feature(cxx_static_assert)</tt> or
<tt>__has_extension(cxx_static_assert)</tt> to determine if support for
compile-time assertions using <tt>static_assert</tt> is enabled.</p>
-<h4 id="cxx_auto_type">C++0x type inference</h3>
+<h4 id="cxx_auto_type">C++0x type inference</h4>
<p>Use <tt>__has_feature(cxx_auto_type)</tt> or
<tt>__has_extension(cxx_auto_type)</tt> to determine C++0x type inference is
supported using the <tt>auto</tt> specifier. If this is disabled, <tt>auto</tt>
will instead be a storage class specifier, as in C or C++98.</p>
-<h4 id="cxx_variadic_templates">C++0x variadic templates</h3>
+<h4 id="cxx_variadic_templates">C++0x variadic templates</h4>
<p>Use <tt>__has_feature(cxx_variadic_templates)</tt> or
<tt>__has_extension(cxx_variadic_templates)</tt> to determine if support
for variadic templates is enabled.</p>
-<h4 id="cxx_inline_namespaces">C++0x inline namespaces</h3>
+<h4 id="cxx_inline_namespaces">C++0x inline namespaces</h4>
<p>Use <tt>__has_feature(cxx_inline_namespaces)</tt> or
<tt>__has_extension(cxx_inline_namespaces)</tt> to determine if support for
inline namespaces is enabled.</p>
-<h4 id="cxx_trailing_return">C++0x trailing return type</h3>
+<h4 id="cxx_trailing_return">C++0x trailing return type</h4>
<p>Use <tt>__has_feature(cxx_trailing_return)</tt> or
<tt>__has_extension(cxx_trailing_return)</tt> to determine if support for the
alternate function declaration syntax with trailing return type is enabled.</p>
-<h4 id="cxx_noexcept">C++0x noexcept</h3>
+<h4 id="cxx_noexcept">C++0x noexcept</h4>
<p>Use <tt>__has_feature(cxx_noexcept)</tt> or
<tt>__has_extension(cxx_noexcept)</tt> to determine if support for noexcept
exception specifications is enabled.</p>
-<h4 id="cxx_strong_enums">C++0x strongly typed enumerations</h3>
+<h4 id="cxx_strong_enums">C++0x strongly typed enumerations</h4>
<p>Use <tt>__has_feature(cxx_strong_enums)</tt> or
<tt>__has_extension(cxx_strong_enums)</tt> to determine if support for
@@ -530,7 +541,7 @@ strongly typed, scoped enumerations is enabled.</p>
C1X standard. As a result, all these features are enabled
with the <tt>-std=c1x</tt> option when compiling C code.</p>
-<h4 id="c_generic_selections">C1X generic selections</h2>
+<h4 id="c_generic_selections">C1X generic selections</h4>
<p>Use <tt>__has_feature(c_generic_selections)</tt> or
<tt>__has_extension(c_generic_selections)</tt> to determine if support for
@@ -544,7 +555,7 @@ C1X draft standard.</p>
appropriate standard, but in C++, which lacks the type compatibility rules
used in C, types are considered compatible only if they are equivalent.</p>
-<h4 id="c_static_assert">C1X <tt>_Static_assert()</tt></h3>
+<h4 id="c_static_assert">C1X <tt>_Static_assert()</tt></h4>
<p>Use <tt>__has_feature(c_static_assert)</tt> or
<tt>__has_extension(c_static_assert)</tt> to determine if support for
@@ -554,7 +565,7 @@ compile-time assertions using <tt>_Static_assert</tt> is enabled.</p>
<h2 id="checking_type_traits">Checks for Type Traits</h2>
<!-- ======================================================================= -->
-<p>Clang supports the <a hef="http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html">GNU C++ type traits</a> and a subset of the <a href="http://msdn.microsoft.com/en-us/library/ms177194(v=VS.100).aspx">Microsoft Visual C++ Type traits</a>. For each supported type trait <code>__X</code>, <code>__has_extension(X)</code> indicates the presence of the type trait. For example:
+<p>Clang supports the <a href="http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html">GNU C++ type traits</a> and a subset of the <a href="http://msdn.microsoft.com/en-us/library/ms177194(v=VS.100).aspx">Microsoft Visual C++ Type traits</a>. For each supported type trait <code>__X</code>, <code>__has_extension(X)</code> indicates the presence of the type trait. For example:
<blockquote>
<pre>
#if __has_extension(is_convertible_to)
@@ -640,7 +651,7 @@ to have the type <code>NSArray *</code>. If neither <code>alloc</code> nor <code
<p>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</p>
<ul>
@@ -650,7 +661,7 @@ type is compatible with the type of its class and if
<li>the first word is "autorelease", "init", "retain", or "self",
and the method is an instance method.</li>
-</ul></p>
+</ul>
<p>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
@@ -670,6 +681,12 @@ with a related result type is treated the same way as method without a
related result type.</p>
<!-- ======================================================================= -->
+<h2 id="objc_arc">Automatic reference counting </h2>
+<!-- ======================================================================= -->
+
+<p>Clang provides support for <a href="AutomaticReferenceCounting.html">automated reference counting</a> in Objective-C, which eliminates the need for manual retain/release/autorelease message sends. There are two feature macros associated with automatic reference counting: <code>__has_feature(objc_arc)</code> indicates the availability of automated reference counting in general, while <code>__has_feature(objc_arc_weak)</code> indicates that automated reference counting also includes support for <code>__weak</code> pointers to Objective-C objects.</p>
+
+<!-- ======================================================================= -->
<h2 id="overloading-in-c">Function Overloading in C</h2>
<!-- ======================================================================= -->
@@ -790,7 +807,7 @@ vector support</a> instead of builtins, in order to reduce the number of
builtins that we need to implement.</p>
<!-- ======================================================================= -->
-<h3 id="__builtin_shufflevector">__builtin_shufflevector</h3>
+<h3><a name="__builtin_shufflevector">__builtin_shufflevector</a></h3>
<!-- ======================================================================= -->
<p><tt>__builtin_shufflevector</tt> is used to express generic vector
@@ -842,7 +859,7 @@ the number of indices specified.
<p>Query for this feature with __has_builtin(__builtin_shufflevector).</p>
<!-- ======================================================================= -->
-<h3 id="__builtin_unreachable">__builtin_unreachable</h3>
+<h3><a name="__builtin_unreachable">__builtin_unreachable</a></h3>
<!-- ======================================================================= -->
<p><tt>__builtin_unreachable</tt> is used to indicate that a specific point in
@@ -880,7 +897,7 @@ no arguments and produces a void result.
<p>Query for this feature with __has_builtin(__builtin_unreachable).</p>
<!-- ======================================================================= -->
-<h3 id="__sync_swap">__sync_swap</h3>
+<h3><a name="__sync_swap">__sync_swap</a></h3>
<!-- ======================================================================= -->
<p><tt>__sync_swap</tt> is used to atomically swap integers or pointers in
@@ -896,7 +913,7 @@ memory.
<p><b>Example of Use:</b></p>
<pre>
-int old_value = __sync_swap(&value, new_value);
+int old_value = __sync_swap(&amp;value, new_value);
</pre>
<p><b>Description:</b></p>
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.</li>
<li>The Apple "blocks" extension is recognized by default in gnu* modes
on some platforms; it can be enabled in any mode with the "-fblocks"
option.</li>
+<li>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.</li>
</ul>
<p>Differences between *89 and *99 modes:</p>
@@ -882,11 +886,6 @@ extensions are not implemented yet:</p>
the uses described in the bug, this is likely to be implemented at some
point, at least partially.</li>
-<li>clang does not support code generation for local variables pinned to
-registers (<a href="http://llvm.org/bugs/show_bug.cgi?id=3933">bug 3933</a>).
-This is a relatively small feature, so it is likely to be implemented
-relatively soon.</li>
-
<li>clang does not support decimal floating point types (_Decimal32 and
friends) or fixed-point types (_Fract and friends); nobody has expressed
interest in these features yet, so it's hard to say when they will be
@@ -937,16 +936,9 @@ extension appears to be rarely used. Note that clang <em>does</em> support
flexible array members (arrays with a zero or unspecified size at the end of
a structure).</li>
-<li>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.</li>
-
<li>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.</li>
+constant expression is required, like "x-x" where x is a variable.</li>
<li>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 @@
-<title>'clang' C frontend documentation</title>
-
-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
};
/**
@@ -933,6 +943,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
@@ -1474,6 +1521,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.
*/
@@ -2830,6 +2882,137 @@ enum CXCodeComplete_Flags {
};
/**
+ * \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().
*/
@@ -2950,6 +3133,19 @@ 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);
+
+/**
* @}
*/
@@ -3005,6 +3201,51 @@ CINDEX_LINKAGE void clang_getInclusions(CXTranslationUnit tu,
* @}
*/
+/** \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<std::pair<std::string,std::string> > &remap,
+ llvm::StringRef outputDir,
+ DiagnosticClient *DiagClient);
+
+typedef void (*TransformFn)(MigrationPass &pass);
+
+std::vector<TransformFn> 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<FileManager> FileMgr;
+
+ typedef llvm::PointerUnion<const FileEntry *, llvm::MemoryBuffer *> Target;
+ typedef llvm::DenseMap<const FileEntry *, Target> MappingsTy;
+ MappingsTy FromToMappings;
+
+ llvm::DenseMap<const FileEntry *, const FileEntry *> 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<ASTContext> {
mutable llvm::FoldingSet<QualifiedTemplateName> QualifiedTemplateNames;
mutable llvm::FoldingSet<DependentTemplateName> DependentTemplateNames;
- mutable llvm::FoldingSet<SubstTemplateTemplateParmPackStorage>
+ mutable llvm::FoldingSet<SubstTemplateTemplateParmStorage>
+ SubstTemplateTemplateParms;
+ mutable llvm::ContextualFoldingSet<SubstTemplateTemplateParmPackStorage,
+ ASTContext&>
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<char> &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<char> &Output,
+ void *Cookie,
+ llvm::SmallVectorImpl<intptr_t> &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<EvaluatedStmt *>();
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 <typename T>
+ void dropAttr() {
+ if (!HasAttrs) return;
+
+ AttrVec &Attrs = getAttrs();
+ for (unsigned i = 0, e = Attrs.size(); i != e; /* in loop */) {
+ if (isa<T>(Attrs[i])) {
+ Attrs.erase(Attrs.begin() + i);
+ --e;
+ }
+ else
+ ++i;
+ }
+ if (Attrs.empty())
+ HasAttrs = false;
+ }
+
template <typename T>
specific_attr_iterator<T> specific_attr_begin() const {
return specific_attr_iterator<T>(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<ArcWeakrefUnavailableAttr>())
+ 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<TemplateSpecializationKind>(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<typename T>
+ /// 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<Expr>(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<Expr*>(this)->IgnoreImpCasts();
+ }
const Expr *IgnoreParens() const {
return const_cast<Expr*>(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<ImplicitCastExpr>(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<designators_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_designators_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<Expr>(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<Expr>(Op); }
Expr *getSubExpr() { return cast_or_null<Expr>(Op); }
- void setSubExpr(Expr *E) { Op = E; }
SourceLocation getThrowLoc() const { return ThrowLoc; }
- void setThrowLoc(SourceLocation L) { ThrowLoc = L; }
+ /// \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<Expr **>(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<unsigned> 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<Expr>(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<Expr *>(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<Expr>(Operand); }
+ const Expr *getSubExpr() const { return cast<Expr>(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<ObjCBridgeCastKind>(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<Decl*> &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<Decl*> &Result) {
return FindExternalLexicalDecls(DC, 0, Result);
}
template <typename DeclTy>
- bool FindExternalLexicalDeclsBy(const DeclContext *DC,
- llvm::SmallVectorImpl<Decl*> &Result) {
+ ExternalLoadResult FindExternalLexicalDeclsBy(const DeclContext *DC,
+ llvm::SmallVectorImpl<Decl*> &Result) {
return FindExternalLexicalDecls(DC, DeclTy::classofKind, Result);
}
diff --git a/lib/CodeGen/GlobalDecl.h b/include/clang/AST/GlobalDecl.h
index c2f36d210bfc..c43e44c26f31 100644
--- a/lib/CodeGen/GlobalDecl.h
+++ b/include/clang/AST/GlobalDecl.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_CODEGEN_GLOBALDECL_H
-#define CLANG_CODEGEN_GLOBALDECL_H
+#ifndef LLVM_CLANG_AST_GLOBALDECL_H
+#define LLVM_CLANG_AST_GLOBALDECL_H
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
@@ -21,8 +21,6 @@
namespace clang {
-namespace CodeGen {
-
/// GlobalDecl - represents a global declaration. This can either be a
/// CXXConstructorDecl and the constructor type (Base, Complete).
/// a CXXDestructorDecl and the destructor type (Base, Complete) or
@@ -89,28 +87,27 @@ public:
}
};
-} // end namespace CodeGen
} // end namespace clang
namespace llvm {
template<class> struct DenseMapInfo;
- template<> struct DenseMapInfo<clang::CodeGen::GlobalDecl> {
- static inline clang::CodeGen::GlobalDecl getEmptyKey() {
- return clang::CodeGen::GlobalDecl();
+ template<> struct DenseMapInfo<clang::GlobalDecl> {
+ static inline clang::GlobalDecl getEmptyKey() {
+ return clang::GlobalDecl();
}
- static inline clang::CodeGen::GlobalDecl getTombstoneKey() {
- return clang::CodeGen::GlobalDecl::
+ static inline clang::GlobalDecl getTombstoneKey() {
+ return clang::GlobalDecl::
getFromOpaquePtr(reinterpret_cast<void*>(-1));
}
- static unsigned getHashValue(clang::CodeGen::GlobalDecl GD) {
+ static unsigned getHashValue(clang::GlobalDecl GD) {
return DenseMapInfo<void*>::getHashValue(GD.getAsOpaquePtr());
}
- static bool isEqual(clang::CodeGen::GlobalDecl LHS,
- clang::CodeGen::GlobalDecl RHS) {
+ static bool isEqual(clang::GlobalDecl LHS,
+ clang::GlobalDecl RHS) {
return LHS == RHS;
}
@@ -119,7 +116,7 @@ namespace llvm {
// GlobalDecl isn't *technically* a POD type. However, its copy constructor,
// copy assignment operator, and destructor are all trivial.
template <>
- struct isPodLike<clang::CodeGen::GlobalDecl> {
+ struct isPodLike<clang::GlobalDecl> {
static const bool value = true;
};
} // end namespace llvm
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<Stmt*>(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 <anonymous at t.h:10:5>"). Otherwise, just
/// prints "<anonymous>" 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<T> 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<OverloadedTemplateStorage *>(this)
: 0;
}
+ SubstTemplateTemplateParmStorage *getAsSubstTemplateTemplateParm() {
+ return Bits.Kind == SubstTemplateTemplateParm
+ ? reinterpret_cast<SubstTemplateTemplateParmStorage *>(this)
+ : 0;
+ }
+
SubstTemplateTemplateParmPackStorage *getAsSubstTemplateTemplateParmPack() {
- return Bits.IsOverloadedStorage
- ? 0
- : reinterpret_cast<SubstTemplateTemplateParmPackStorage *>(this) ;
+ return Bits.Kind == SubstTemplateTemplateParmPack
+ ? reinterpret_cast<SubstTemplateTemplateParmPackStorage *>(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<NamedDecl **>(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<UncommonTemplateNameStorage *>())
+ return uncommon->getAsSubstTemplateTemplateParm();
+
+ return 0;
+ }
+
/// \brief Retrieve the substituted template template parameter pack, if
/// known.
///
@@ -260,9 +287,15 @@ public:
return Storage.dyn_cast<DependentTemplateName *>();
}
+ 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<unsigned char>(Bits)) {}
+ ExtInfo(unsigned Bits) : Bits(static_cast<uint16_t>(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<Expr * const *>(arg_type_end());
+ if (getExceptionSpecType() != EST_ComputedNoexcept)
+ eh_end += NumExceptions;
+ else
+ eh_end += 1; // NoexceptExpr
+
+ return reinterpret_cast<const bool*>(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<UnresolvedUsingTypenameDecl*>(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<TypedefNameDecl*>(D)) {
assert(!isa<TypedefType>(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<TypedefType>(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<int>. Some
-/// template specialization types are syntactic sugar, whose canonical
-/// type will point to some other type node that represents the
-/// instantiation or class template specialization. For example, a
-/// class template specialization type of @c vector<int> will refer to
-/// a tag type for the instantiation
-/// @c std::vector<int, std::allocator<int>>.
+/// A non-dependent template specialization type is always "sugar",
+/// typically for a @c RecordType. For example, a class template
+/// specialization type of @c vector<int> will refer to a tag type for
+/// the instantiation @c std::vector<int, std::allocator<int>>
///
-/// Other template specialization types, for which the template name
-/// is dependent, may be canonical types. These types are always
-/// dependent.
+/// 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<unsigned> 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 <typename T>
+ bool delayDelete(T *ptr) {
+ return delayCleanup(ptr, cleanupWithDelete<T>);
+ }
+
+ template <typename T, void (T::*Fn)()>
+ bool delayMemberFunc(T *ptr) {
+ return delayCleanup(ptr, cleanupWithMemberFunc<T, Fn>);
+ }
+
+ void doCleanup() {
+ for (llvm::SmallVector<std::pair<void *, CleanupFn>, 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<void *, CleanupFn> Ptrs;
+ llvm::SmallVector<std::pair<void *, CleanupFn>, 8> Cleanups;
+
+ template <typename T>
+ static void cleanupWithDelete(void *ptr) {
+ delete static_cast<T *>(ptr);
+ }
+
+ template <typename T, void (T::*Fn)()>
+ static void cleanupWithMemberFunc(void *ptr) {
+ (static_cast<T *>(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<char> &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<char> &Output,
+ void *Cookie,
+ llvm::SmallVectorImpl<intptr_t> &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<char> &Output) const {
+ llvm::SmallVectorImpl<char> &Output,
+ llvm::SmallVectorImpl<intptr_t> &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<DiagGroup<"dynamic-class-memaccess">>;
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<DiagGroup<"sizeof-pointer-memaccess">>;
+def warn_sizeof_pointer_type_memaccess : Warning<
+ "argument to 'sizeof' in %0 call is the same pointer type %1 as the "
+ "%select{destination|source}2; expected %3 or an explicit length">,
+ InGroup<DiagGroup<"sizeof-pointer-memaccess">>;
/// 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<GNU>;
+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<AutomaticReferenceCountingABI>,
+ DefaultIgnore;
+def warn_arc_retained_assign : Warning<
+ "assigning retained object to %select{weak|unsafe_unretained}0 variable"
+ "; object will be released after assignment">,
+ InGroup<ARCUnsafeRetainedAssign>;
+def warn_arc_retained_property_assign : Warning<
+ "assigning retained object to unsafe property"
+ "; object will be released after assignment">,
+ InGroup<ARCUnsafeRetainedAssign>;
+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<AutomaticReferenceCountingABI>, 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<AutomaticReferenceCountingABI>, 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<AutomaticReferenceCounting>;
+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<ARCRetainCycles>;
+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<ARCNonPodMemAccess>;
+
+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<DiagGroup<"shift-overflow">>;
-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<DiagGroup<"shift-overflow">>;
+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<DiagGroup<"shift-sign-overflow">>, 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<Parentheses>;
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<DiagGroup<"constant-logical-operand">>;
+def warn_bitwise_and_in_bitwise_or : Warning<
+ "'&' within '|'">, InGroup<BitwiseOpParentheses>;
+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<LogicalOpParentheses>;
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<SelfAssignment>, DefaultIgnore;
+def warn_sizeof_array_param : Warning<
+ "sizeof on array function parameter will return size of %0 instead of %1">,
+ InGroup<SizeofArrayArgument>;
+
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<PointerArith>;
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<DiagGroup<"enum-compare">>;
+def warn_null_in_arithmetic_operation : Warning<
+ "use of NULL in arithmetic operation">,
+ InGroup<DiagGroup<"null-arithmetic">>;
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<PointerArith>;
+ "arithmetic on%select{ a|}0 pointer%select{|s}0 to void is a GNU extension">,
+ InGroup<PointerArith>;
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<PointerArith>;
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<ObjCNonUnifiedException>;
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<GNU>;
@@ -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<EmptyBody>;
+
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<DiagGroup<"non-pod-varargs">>, DefaultError;
+def warn_second_parameter_to_va_arg_never_compatible : Warning<
+ "second argument to 'va_arg' is of promotable type %0; this va_arg has "
+ "undefined behavior because arguments will be promoted to %1">;
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<ReturnType>;
def ext_return_has_expr : ExtWarn<
- "void %select{function|method}1 %0 should not return a value">, DefaultError,
- InGroup<ReturnType>;
+ "%select{void function|void method|constructor|destructor}1 %0 "
+ "should not return a value">,
+ DefaultError, InGroup<ReturnType>;
def ext_return_has_void_expr : Extension<
"void %select{function|method}1 %0 should not return void expression">;
def warn_noreturn_function_has_return_expr : Warning<
@@ -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 <sys/types.h>
+#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<IdentifierInfo*> &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<SourceLocation,SourceLocation> 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 FileEntry*, SrcMgr::ContentCache*>
::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<FileID, unsigned>
- getDecomposedInstantiationLocSlowCase(const SrcMgr::SLocEntry *E,
- unsigned Offset) const;
+ getDecomposedInstantiationLocSlowCase(const SrcMgr::SLocEntry *E) const;
std::pair<FileID, unsigned>
getDecomposedSpellingLocSlowCase(const SrcMgr::SLocEntry *E,
unsigned Offset) const;
diff --git a/include/clang/Basic/SourceManagerInternals.h b/include/clang/Basic/SourceManagerInternals.h
index 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<OverloadExpr>;
def CXXNoexceptExpr : DStmt<Expr>;
def PackExpansionExpr : DStmt<Expr>;
def SizeOfPackExpr : DStmt<Expr>;
+def SubstNonTypeTemplateParmExpr : DStmt<Expr>;
def SubstNonTypeTemplateParmPackExpr : DStmt<Expr>;
+def MaterializeTemporaryExpr : DStmt<Expr>;
// Obj-C Expressions.
def ObjCStringLiteral : DStmt<Expr>;
@@ -130,6 +133,10 @@ def ObjCProtocolExpr : DStmt<Expr>;
def ObjCIvarRefExpr : DStmt<Expr>;
def ObjCPropertyRefExpr : DStmt<Expr>;
def ObjCIsaExpr : DStmt<Expr>;
+def ObjCIndirectCopyRestoreExpr : DStmt<Expr>;
+
+// Obj-C ARC Expressions.
+def ObjCBridgedCastExpr : DStmt<ExplicitCastExpr>;
// CUDA Expressions.
def CUDAKernelCallExpr : DStmt<CallExpr>;
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<coverage_file>;
+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<"<N>">,
def ferror_limit : Separate<"-ferror-limit">, MetaVarName<"<N>">,
HelpText<"Set the maximum number of errors to emit before stopping (0 = no limit).">;
def fmacro_backtrace_limit : Separate<"-fmacro-backtrace-limit">, MetaVarName<"<N>">,
- 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<"<N>">,
HelpText<"Set the maximum number of entries to print in a template instantiation backtrace (0 = no limit).">;
def fmessage_length : Separate<"-fmessage-length">, MetaVarName<"<N>">,
@@ -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<Kind>(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<ccc_arcmt_check>;
+def ccc_arrmt_modify : Flag<"-ccc-arrmt-modify">, Alias<ccc_arcmt_modify>;
+def ccc_arcmt_migrate : Separate<"-ccc-arcmt-migrate">, CCCDriverOpt,
+ HelpText<"Apply modifications and produces temporary files that conform to ARC">;
+def ccc_arcmt_migrate_EQ : Joined<"-ccc-arcmt-migrate=">, CCCDriverOpt,
+ Alias<ccc_arcmt_migrate>;
+
// Make sure all other -ccc- options are rejected.
def ccc_ : Joined<"-ccc-">, Group<ccc_Group>, Flags<[Unsupported]>;
@@ -382,6 +393,10 @@ def fno_verbose_asm : Flag<"-fno-verbose-asm">, Group<f_Group>;
def fno_working_directory : Flag<"-fno-working-directory">, Group<f_Group>;
def fno_wrapv : Flag<"-fno-wrapv">, Group<f_Group>;
def fno_zero_initialized_in_bss : Flag<"-fno-zero-initialized-in-bss">, Group<f_Group>;
+def fobjc_arc : Flag<"-fobjc-arc">, Group<f_Group>;
+def fno_objc_arc : Flag<"-fno-objc-arc">, Group<f_Group>;
+def fobjc_arc_exceptions : Flag<"-fobjc-arc-exceptions">, Group<f_Group>;
+def fno_objc_arc_exceptions : Flag<"-fno-objc-arc-exceptions">, Group<f_Group>;
def fobjc_atdefs : Flag<"-fobjc-atdefs">, Group<clang_ignored_f_Group>;
def fobjc_call_cxx_cdtors : Flag<"-fobjc-call-cxx-cdtors">, Group<clang_ignored_f_Group>;
def fobjc_default_synthesize_properties :
@@ -409,6 +424,7 @@ def fomit_frame_pointer : Flag<"-fomit-frame-pointer">, Group<f_Group>;
def fopenmp : Flag<"-fopenmp">, Group<f_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<f_Group>;
def fpascal_strings : Flag<"-fpascal-strings">, Group<f_Group>;
def fpch_preprocess : Flag<"-fpch-preprocess">, Group<f_Group>;
@@ -803,8 +819,8 @@ def _specs : Separate<"--specs">, Alias<specs_EQ>;
def _static : Flag<"--static">, Alias<static>;
def _std_EQ : Joined<"--std=">, Alias<std_EQ>;
def _std : Separate<"--std">, Alias<std_EQ>;
-def _stdlib_EQ : Joined<"--stdlib=">, Alias<std_EQ>;
-def _stdlib : Separate<"--stdlib">, Alias<std_EQ>;
+def _stdlib_EQ : Joined<"--stdlib=">, Alias<stdlib_EQ>;
+def _stdlib : Separate<"--stdlib">, Alias<stdlib_EQ>;
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<Diagnostic> &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<ASTUnit> 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<FrontendAction> 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<std::pair<InputKind, std::string> > 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<std::pair<std::string, std::string> >::iterator
remapped_file_iterator;
typedef std::vector<std::pair<std::string, std::string> >::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<char> &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<Token, 8> 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 <string>
@@ -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 <vector>
@@ -120,7 +121,7 @@ class Preprocessor : public llvm::RefCountedBase<Preprocessor> {
/// 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<Preprocessor> {
/// previous macro value.
llvm::DenseMap<IdentifierInfo*, std::vector<MacroInfo*> > 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<Preprocessor> {
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<Token, 16> MacroExpandedTokens;
+ std::vector<std::pair<TokenLexer *, size_t> > 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<Token> 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<FileID, unsigned> 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<IdentifierInfo *> &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<IdentifierInfo *> &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<IdentifierInfo *> &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<IdentifierInfo *> &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<DeclaratorChunk::ParamInfo, 16> &ParamInfo);
+ void ParseParameterDeclarationClause(
+ Declarator &D,
+ ParsedAttributes &attrs,
+ llvm::SmallVector<DeclaratorChunk::ParamInfo, 16> &ParamInfo,
+ SourceLocation &EllipsisLoc);
void ParseBracketDeclarator(Declarator &D);
//===--------------------------------------------------------------------===//
@@ -1766,7 +1764,8 @@ bool ParseAsmOperandsOpt(llvm::SmallVectorImpl<IdentifierInfo *> &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<IdentifierInfo *> &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<const FunctionDecl*, VisitFlag> 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<int>.
- 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<ExceptionSpecificationType>(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<Declarator*>(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<AccessedEntity*>(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<ObjCMethodList,ObjCMethodList> 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<NamespaceDecl *> &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<NSConsumedAttr>());
+
+ InitializedEntity Entity;
+ Entity.Kind = EK_Parameter;
+ Entity.Type = Context.getVariableArrayDecayedType(
+ Parm->getType().getUnqualifiedType());
+ Entity.Parent = 0;
+ Entity.Parameter
+ = (static_cast<uintptr_t>(Consumed) | reinterpret_cast<uintptr_t>(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 T> 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<llvm::PointerUnion<const TemplateTypeParmType*, NamedDecl*>,
@@ -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<SourceLocation, PartialDiagnostic> 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<NamespaceDecl*, bool> 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<DeducedTemplateArgument> &Deduced,
unsigned NumExplicitlySpecified,
FunctionDecl *&Specialization,
- sema::TemplateDeductionInfo &Info);
+ sema::TemplateDeductionInfo &Info,
+ llvm::SmallVectorImpl<OriginalCallArg> 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<IdentifierInfo *, std::pair<llvm::StringRef, bool> >
+ typedef llvm::DenseMap<IdentifierInfo *, TypoCorrection>
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 <XXX>" = "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<CodeCompletionResult> &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 <class DeclClass>
+ DeclClass *getCorrectionDeclAs() const {
+ return dyn_cast_or_null<DeclClass>(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<uint64_t, 1> OpenCLExtensions;
+ /// \brief A list of the namespaces we've seen.
+ llvm::SmallVector<uint64_t, 4> 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<Decl*> &Decls);
@@ -1125,6 +1128,11 @@ public:
virtual std::pair<ObjCMethodList, ObjCMethodList>
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<NamespaceDecl *> &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<Decl*> &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<T>*) *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<unsigned> 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<unsigned> 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<CompilerInvocation> 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<TransformFn> transforms = arcmt::getAllTransformations();
+ assert(!transforms.empty());
+
+ llvm::OwningPtr<CompilerInvocation> 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<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ llvm::IntrusiveRefCntPtr<Diagnostic> Diags(
+ new Diagnostic(DiagID, DiagClient, /*ShouldOwnClient=*/false));
+
+ // Filter of all diagnostics.
+ CaptureDiagnosticClient errRec(*Diags, capturedDiags);
+ Diags->setClient(&errRec, /*ShouldOwnClient=*/false);
+
+ llvm::OwningPtr<ASTUnit> 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<SourceLocation> 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<TransformFn> 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<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ llvm::IntrusiveRefCntPtr<Diagnostic> 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<std::pair<std::string,std::string> > &
+ remap,
+ llvm::StringRef outputDir,
+ DiagnosticClient *DiagClient) {
+ assert(!outputDir.empty());
+
+ llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ llvm::IntrusiveRefCntPtr<Diagnostic> 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<SourceLocation> &ARCMTMacroLocs;
+
+public:
+ ARCMTMacroTrackerPPCallbacks(std::vector<SourceLocation> &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<SourceLocation> &ARCMTMacroLocs;
+
+public:
+ ARCMTMacroTrackerAction(std::vector<SourceLocation> &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<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ llvm::IntrusiveRefCntPtr<Diagnostic> Diags(
+ new Diagnostic(DiagID, DiagClient, /*ShouldOwnClient=*/false));
+ Remapper.initFromDisk(outputDir, *Diags, /*ignoreIfFilesChanges=*/true);
+ }
+}
+
+bool MigrationProcess::applyTransform(TransformFn trans,
+ RewriteListener *listener) {
+ llvm::OwningPtr<CompilerInvocation> CInvok;
+ CInvok.reset(createInvocationForMigration(OrigCI));
+ CInvok->getDiagnosticOpts().IgnoreWarnings = true;
+
+ Remapper.applyMappings(*CInvok);
+
+ CapturedDiagList capturedDiags;
+ std::vector<SourceLocation> ARCMTMacroLocs;
+
+ assert(DiagClient);
+ llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ llvm::IntrusiveRefCntPtr<Diagnostic> Diags(
+ new Diagnostic(DiagID, DiagClient, /*ShouldOwnClient=*/false));
+
+ // Filter of all diagnostics.
+ CaptureDiagnosticClient errRec(*Diags, capturedDiags);
+ Diags->setClient(&errRec, /*ShouldOwnClient=*/false);
+
+ llvm::OwningPtr<ARCMTMacroTrackerAction> ASTAction;
+ ASTAction.reset(new ARCMTMacroTrackerAction(ARCMTMacroLocs));
+
+ llvm::OwningPtr<ASTUnit> 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 <fstream>
+
+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<std::pair<const FileEntry *, const FileEntry *> > pairs;
+
+ std::ifstream fin(infoFile.c_str());
+ if (!fin.good())
+ return report(std::string("Error opening file: ") + infoFile, Diag);
+
+ while (true) {
+ std::string fromFilename, toFilename;
+ uint64_t timeModified;
+
+ fin >> fromFilename >> timeModified >> toFilename;
+ if (fin.eof())
+ break;
+ if (!fin.good())
+ return report(std::string("Error in format of file: ") + infoFile, Diag);
+
+ 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<const FileEntry *>()) {
+ 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<llvm::MemoryBuffer *>();
+ 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<const FileEntry *>()) {
+ if (fs::copy_file(newFE->getName(), origFE->getName(),
+ fs::copy_option::overwrite_if_exists) != llvm::errc::success) {
+ std::string err = "Could not copy file '";
+ llvm::raw_string_ostream os(err);
+ os << "Could not copy file '" << newFE->getName() << "' to file '"
+ << origFE->getName() << "'";
+ os.flush();
+ return report(err, Diag);
+ }
+ } 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<llvm::MemoryBuffer *>();
+ 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<const FileEntry *>()) {
+ PPOpts.addRemappedFile(I->first->getName(), FE->getName());
+ } else {
+ llvm::MemoryBuffer *mem = I->second.get<llvm::MemoryBuffer *>();
+ 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<const FileEntry *>()) {
+ PPOpts.addRemappedFile(I->first->getName(), FE->getName());
+ } else {
+ llvm::MemoryBuffer *mem = I->second.get<llvm::MemoryBuffer *>();
+ 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<const FileEntry *, const FileEntry *>::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<llvm::MemoryBuffer *>()) {
+ delete oldmem;
+ } else {
+ const FileEntry *toFE = targ.get<const FileEntry *>();
+ llvm::DenseMap<const FileEntry *, const FileEntry *>::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<StoredDiagnostic> ListTy;
+ ListTy List;
+
+public:
+ void push_back(const StoredDiagnostic &diag) { List.push_back(diag); }
+
+ bool clearDiagnostic(llvm::ArrayRef<unsigned> IDs, SourceRange range);
+ bool hasDiagnostic(llvm::ArrayRef<unsigned> IDs, SourceRange range) const;
+
+ 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<unsigned> IDs, SourceRange range);
+ bool clearAllDiagnostics(SourceRange range) {
+ return clearDiagnostic(llvm::ArrayRef<unsigned>(), 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<SourceLocation> &ARCMTMacroLocs;
+
+ MigrationPass(ASTContext &Ctx, Sema &sema, TransformActions &TA,
+ std::vector<SourceLocation> &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<ARCAssignChecker> {
+ MigrationPass &Pass;
+ llvm::DenseSet<VarDecl *> 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<DeclRefExpr>(E->IgnoreParenCasts());
+ if (declRef && isa<VarDecl>(declRef->getDecl())) {
+ ASTContext &Ctx = Pass.Ctx;
+ Expr::isModifiableLvalueResult IsLV = E->isModifiableLvalue(Ctx, &Loc);
+ if (IsLV != Expr::MLV_ConstQualified)
+ return true;
+ VarDecl *var = cast<VarDecl>(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 <map>
+
+using namespace clang;
+using namespace arcmt;
+using namespace trans;
+using llvm::StringRef;
+
+namespace {
+
+class ReleaseCollector : public RecursiveASTVisitor<ReleaseCollector> {
+ Decl *Dcl;
+ llvm::SmallVectorImpl<ObjCMessageExpr *> &Releases;
+
+public:
+ ReleaseCollector(Decl *D, llvm::SmallVectorImpl<ObjCMessageExpr *> &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<DeclRefExpr>(instance)) {
+ if (DE->getDecl() == Dcl)
+ Releases.push_back(E);
+ }
+ return true;
+ }
+};
+
+}
+
+namespace {
+
+class AutoreleasePoolRewriter
+ : public RecursiveASTVisitor<AutoreleasePoolRewriter> {
+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<VarDecl *, 8> VarsToHandle;
+
+ for (std::map<VarDecl *, PoolVarInfo>::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<PoolScope>::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<PoolScope>::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<PoolScope>::iterator
+ scpI = info.Scopes.begin(),
+ scpE = info.Scopes.end(); scpI != scpE; ++scpI) {
+ PoolScope &scope = *scpI;
+ for (llvm::SmallVectorImpl<ObjCMessageExpr *>::iterator
+ relI = scope.Releases.begin(),
+ relE = scope.Releases.end(); relI != relE; ++relI) {
+ clearUnavailableDiags(*relI);
+ Pass.TA.removeStmt(*relI);
+ }
+ }
+ }
+ }
+
+ bool VisitCompoundStmt(CompoundStmt *S) {
+ llvm::SmallVector<PoolScope, 4> 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<DeclStmt>(child)) {
+ if (DclS->isSingleDecl()) {
+ if (VarDecl *VD = dyn_cast<VarDecl>(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<BinaryOperator>(child)) {
+ if (DeclRefExpr *dref = dyn_cast<DeclRefExpr>(bop->getLHS())) {
+ if (VarDecl *VD = dyn_cast<VarDecl>(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<ObjCMessageExpr *, 4> 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<NameReferenceChecker>{
+ 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<ReturnStmt>(*SI))
+ if ((retS->getRetValue() == 0 ||
+ isa<DeclRefExpr>(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<ObjCMessageExpr>(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<ObjCMessageExpr>(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<ObjCMessageExpr>(S);
+ if (!ME) return false;
+ if (ME->getReceiverKind() == ObjCMessageExpr::Instance) {
+ Expr *rec = getEssential(ME->getInstanceReceiver());
+ if (DeclRefExpr *dref = dyn_cast<DeclRefExpr>(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<ObjCInterfaceType>())
+ return isNSAutoreleasePool(interT->getDecl());
+ return false;
+ }
+
+ static Expr *getEssential(Expr *E) {
+ return cast<Expr>(getEssential((Stmt*)E));
+ }
+ static Stmt *getEssential(Stmt *S) {
+ if (ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(S))
+ S = EWC->getSubExpr();
+ if (Expr *E = dyn_cast<Expr>(S))
+ S = E->IgnoreParenCasts();
+ return S;
+ }
+
+ Stmt *Body;
+ MigrationPass &Pass;
+
+ IdentifierInfo *PoolII;
+ Selector DrainSel;
+
+ struct PoolVarInfo {
+ DeclStmt *Dcl;
+ ExprSet Refs;
+ llvm::SmallVector<PoolScope, 2> Scopes;
+
+ PoolVarInfo() : Dcl(0) { }
+ };
+
+ std::map<VarDecl *, PoolVarInfo> PoolVars;
+};
+
+} // anonymous namespace
+
+void trans::rewriteAutoreleasePool(MigrationPass &pass) {
+ BodyTransform<AutoreleasePoolRewriter> 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<RootBlockObjCVarRewriter> {
+ MigrationPass &Pass;
+ llvm::DenseSet<VarDecl *> CheckedVars;
+
+ class BlockVarChecker : public RecursiveASTVisitor<BlockVarChecker> {
+ VarDecl *Var;
+
+ typedef RecursiveASTVisitor<BlockVarChecker> base;
+ public:
+ BlockVarChecker(VarDecl *var) : Var(var) { }
+
+ bool TraverseImplicitCastExpr(ImplicitCastExpr *castE) {
+ if (BlockDeclRefExpr *
+ ref = dyn_cast<BlockDeclRefExpr>(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<VarDecl *, 4> 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<BlocksAttr>();
+ 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<AttributedType>(ty.getTypePtr()))
+ return false;
+ return ty.getLocalQualifiers().getObjCLifetime() == Qualifiers::OCL_Strong;
+ }
+};
+
+class BlockObjCVarRewriter : public RecursiveASTVisitor<BlockObjCVarRewriter> {
+ 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<EmptyChecker, bool> {
+ ASTContext &Ctx;
+ llvm::DenseSet<unsigned> &MacroLocs;
+
+public:
+ EmptyChecker(ASTContext &ctx, llvm::DenseSet<unsigned> &macroLocs)
+ : 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<EmptyStatementsRemover> {
+ MigrationPass &Pass;
+ llvm::DenseSet<unsigned> &MacroLocs;
+
+public:
+ EmptyStatementsRemover(MigrationPass &pass,
+ llvm::DenseSet<unsigned> &macroLocs)
+ : 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<unsigned> &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<unsigned> &MacroLocs) {
+ ASTContext &Ctx = pass.Ctx;
+ TransformActions &TA = pass.TA;
+ DeclContext *DC = Ctx.getTranslationUnitDecl();
+
+ typedef DeclContext::specific_decl_iterator<ObjCImplementationDecl>
+ 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<unsigned> MacroLocs;
+ for (unsigned i = 0, e = pass.ARCMTMacroLocs.size(); i != e; ++i)
+ MacroLocs.insert(pass.ARCMTMacroLocs[i].getRawEncoding());
+
+ EmptyStatementsRemover(pass, MacroLocs)
+ .TraverseDecl(pass.Ctx.getTranslationUnitDecl());
+
+ 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 <map>
+
+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<PropData, 2> PropsTy;
+ typedef std::map<unsigned, PropsTy> 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<ObjCPropertyImplDecl>
+ 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<FileID, unsigned> 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<FileID, unsigned> 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<AttributedType>(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<ImplementationChecker> {
+ 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<RetainReleaseDeallocRemover> {
+ Stmt *Body;
+ MigrationPass &Pass;
+
+ ExprSet Removables;
+ llvm::OwningPtr<ParentMap> 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<ObjCMessageExpr>(E))
+ return (ME->isInstanceMessage() && ME->getSelector() == DelegateSel);
+
+ if (ObjCPropertyRefExpr *propE = dyn_cast<ObjCPropertyRefExpr>(E))
+ return propE->getGetterSelector() == DelegateSel;
+
+ return false;
+ }
+
+ bool isInAtFinally(Expr *E) const {
+ assert(E);
+ Stmt *S = E;
+ while (S) {
+ if (isa<ObjCAtFinallyStmt>(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<ImplicitCastExpr>(parent))
+ return tryRemoving(castE);
+
+ if (ParenExpr *parenE = dyn_cast_or_null<ParenExpr>(parent))
+ return tryRemoving(parenE);
+
+ if (BinaryOperator *
+ bopE = dyn_cast_or_null<BinaryOperator>(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<RetainReleaseDeallocRemover> 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<UnbridgedCastRewriter>{
+ 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<CallExpr>(inner)) {
+ if (FunctionDecl *FD = callE->getDirectCallee()) {
+ if (FD->getAttr<CFReturnsRetainedAttr>()) {
+ castToObjCObject(E, /*retained=*/true);
+ return;
+ }
+ if (FD->getAttr<CFReturnsNotRetainedAttr>()) {
+ 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<CStyleCastExpr>(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<ParenExpr>(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<DeclRefExpr>(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<UnusedInitRewriter> {
+ 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<UnusedInitRewriter> 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<ZeroOutInDeallocRemover> {
+ typedef RecursiveASTVisitor<ZeroOutInDeallocRemover> base;
+
+ MigrationPass &Pass;
+
+ llvm::DenseMap<ObjCPropertyDecl*, ObjCPropertyImplDecl*> 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<DeclRefExpr>(receiver->IgnoreParenCasts());
+ if (!refE || refE->getDecl() != SelfD)
+ return true;
+
+ bool BackedBySynthesizeSetter = false;
+ for (llvm::DenseMap<ObjCPropertyDecl*, ObjCPropertyImplDecl*>::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<ObjCImplDecl>(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<BinaryOperator>(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<ObjCIvarRefExpr>(LHS)) {
+ ObjCIvarDecl *IVDecl = IV->getDecl();
+ if (!IVDecl->getType()->isObjCObjectPointerType())
+ return false;
+ bool IvarBacksPropertySynthesis = false;
+ for (llvm::DenseMap<ObjCPropertyDecl*, ObjCPropertyImplDecl*>::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<ObjCPropertyRefExpr>(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 <map>
+
+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<unsigned, 2> DiagIDs;
+ };
+
+ std::vector<ActionData> 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<StringRef, 2> TextsVec;
+ typedef std::map<FullSourceLoc, TextsVec, FullSourceLoc::BeforeThanCompare>
+ InsertsMap;
+ InsertsMap Inserts;
+ /// \brief A list of ranges to remove. They are always sorted and they never
+ /// intersect with each other.
+ std::list<CharRange> Removals;
+
+ llvm::DenseSet<Stmt *> StmtRemovals;
+
+ std::vector<std::pair<CharRange, SourceLocation> > IndentationRanges;
+
+ /// \brief Keeps text passed to transformation methods.
+ llvm::StringMap<bool> 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<unsigned> 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<unsigned> 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<unsigned> 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<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc);
+
+ // Try to load the file buffer.
+ bool invalidTemp = false;
+ llvm::StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
+ if (invalidTemp)
+ return 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<Expr>(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<unsigned> 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<CharRange>::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<CharRange>::iterator I = Removals.end();
+ while (I != Removals.begin()) {
+ std::list<CharRange>::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<std::pair<CharRange, SourceLocation> >::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<CharRange>::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<bool> &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<TransformActionsImpl*>(Impl);
+}
+
+void TransformActions::startTransaction() {
+ static_cast<TransformActionsImpl*>(Impl)->startTransaction();
+}
+
+bool TransformActions::commitTransaction() {
+ return static_cast<TransformActionsImpl*>(Impl)->commitTransaction();
+}
+
+void TransformActions::abortTransaction() {
+ static_cast<TransformActionsImpl*>(Impl)->abortTransaction();
+}
+
+
+void TransformActions::insert(SourceLocation loc, llvm::StringRef text) {
+ static_cast<TransformActionsImpl*>(Impl)->insert(loc, text);
+}
+
+void TransformActions::insertAfterToken(SourceLocation loc,
+ llvm::StringRef text) {
+ static_cast<TransformActionsImpl*>(Impl)->insertAfterToken(loc, text);
+}
+
+void TransformActions::remove(SourceRange range) {
+ static_cast<TransformActionsImpl*>(Impl)->remove(range);
+}
+
+void TransformActions::removeStmt(Stmt *S) {
+ static_cast<TransformActionsImpl*>(Impl)->removeStmt(S);
+}
+
+void TransformActions::replace(SourceRange range, llvm::StringRef text) {
+ static_cast<TransformActionsImpl*>(Impl)->replace(range, text);
+}
+
+void TransformActions::replace(SourceRange range,
+ SourceRange replacementRange) {
+ static_cast<TransformActionsImpl*>(Impl)->replace(range, replacementRange);
+}
+
+void TransformActions::replaceStmt(Stmt *S, llvm::StringRef text) {
+ static_cast<TransformActionsImpl*>(Impl)->replaceStmt(S, text);
+}
+
+void TransformActions::replaceText(SourceLocation loc, llvm::StringRef text,
+ llvm::StringRef replacementText) {
+ static_cast<TransformActionsImpl*>(Impl)->replaceText(loc, text,
+ replacementText);
+}
+
+void TransformActions::increaseIndentation(SourceRange range,
+ SourceLocation parentIndent) {
+ static_cast<TransformActionsImpl*>(Impl)->increaseIndentation(range,
+ parentIndent);
+}
+
+bool TransformActions::clearDiagnostic(llvm::ArrayRef<unsigned> IDs,
+ SourceRange range) {
+ return static_cast<TransformActionsImpl*>(Impl)->clearDiagnostic(IDs, range);
+}
+
+void TransformActions::applyRewrites(RewriteReceiver &receiver) {
+ static_cast<TransformActionsImpl*>(Impl)->applyRewrites(receiver);
+}
+
+void TransformActions::reportError(llvm::StringRef error, SourceLocation loc,
+ SourceRange range) {
+ assert(!static_cast<TransformActionsImpl*>(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<TransformActionsImpl*>(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 <map>
+
+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<bool>(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<PointerType>())
+ T = ptr->getPointeeType();
+ if (const ObjCObjectPointerType *ObjT = T->getAs<ObjCObjectPointerType>()) {
+ 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<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc);
+
+ // Try to load the file buffer.
+ bool invalidTemp = false;
+ llvm::StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
+ if (invalidTemp)
+ return SourceLocation();
+
+ const char *tokenBegin = file.data() + locInfo.second;
+
+ // Lex from the start of the given location.
+ Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
+ 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<ObjCMessageExpr>(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<DeclRefExpr>(E))
+ return DRE->getDecl()->getDeclContext()->isFileContext();
+ if (ConditionalOperator *condOp = dyn_cast<ConditionalOperator>(E))
+ return isGlobalVar(condOp->getTrueExpr()) &&
+ isGlobalVar(condOp->getFalseExpr());
+
+ return false;
+}
+
+namespace {
+
+class ReferenceClear : public RecursiveASTVisitor<ReferenceClear> {
+ 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<ReferenceCollector> {
+ 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<RemovablesCollector> {
+ 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<LabelStmt>(S))
+ S = Label->getSubStmt();
+ S = S->IgnoreImplicit();
+ if (Expr *E = dyn_cast<Expr>(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<TransformFn> arcmt::getAllTransformations() {
+ std::vector<TransformFn> 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 <typename BODY_TRANS>
+class BodyTransform : public RecursiveASTVisitor<BodyTransform<BODY_TRANS> > {
+ MigrationPass &Pass;
+
+public:
+ BodyTransform(MigrationPass &pass) : Pass(pass) { }
+
+ bool TraverseStmt(Stmt *rootS) {
+ BODY_TRANS(Pass).transformBody(rootS);
+ return true;
+ }
+};
+
+typedef llvm::DenseSet<Expr *> ExprSet;
+
+void clearRefsIn(Stmt *S, ExprSet &refs);
+template <typename iterator>
+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<ExternalASTSource> &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<ObjCInterfaceDecl *>(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<TemplateTemplateParmDecl>(Template))
+ = dyn_cast<TemplateTemplateParmDecl>(Template))
Template = getCanonicalTemplateTemplateParmDecl(TTP);
// The canonical template name is the canonical template declaration.
return TemplateName(cast<TemplateDecl>(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<PointerType>())
+ T = PT->getPointeeType();
+ else if (const ReferenceType *RT = T->getAs<ReferenceType>())
+ 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<RecordType>()) {
@@ -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<FieldDecl>(dcl);
if (FD) {
@@ -4782,6 +4871,24 @@ ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS,
}
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 {
ASTContext &Self = const_cast<ASTContext &>(*this);
@@ -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<TypedefType>(Ty)) {
- if (TypedefNameDecl *TD = TDT->getDecl())
- if (TD->getAttr<ObjCNSObjectAttr>())
- 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<intptr_t> &QualTypeVals) {
// FIXME: Playing with std::string is really slow.
+ bool ForceAKA = false;
+ QualType CanTy = Ty.getCanonicalType();
std::string S = Ty.getAsString(Context.PrintingPolicy);
+ std::string CanS = CanTy.getAsString(Context.PrintingPolicy);
+
+ for (llvm::SmallVectorImpl<intptr_t>::iterator I = QualTypeVals.begin(),
+ E = QualTypeVals.end(); I != E; ++I) {
+ QualType CompareTy =
+ QualType::getFromOpaquePtr(reinterpret_cast<void*>(*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<char> &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<char> &Output,
+ void *Cookie,
+ llvm::SmallVectorImpl<intptr_t> &QualTypeVals) {
ASTContext &Context = *static_cast<ASTContext*>(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<void*>(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<TypeDecl>(DC)) {
S = ConvertTypeToDiagnosticString(Context,
Context.getTypeDeclType(Type),
- PrevArgs, NumPrevArgs);
+ PrevArgs, NumPrevArgs, QualTypeVals);
} else {
// FIXME: Get these strings from some localized place
NamedDecl *ND = cast<NamedDecl>(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<TemplateTemplateParmDecl>(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<FileID, unsigned> 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<VisibilityAttr>());
+}
+
+static bool shouldConsiderTemplateLV(const ClassTemplateSpecializationDecl *d) {
+ return !(d->isExplicitSpecialization() && d->hasAttr<VisibilityAttr>());
+}
+
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<FunctionDecl>(D) || isa<FunctionTemplateDecl>(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<ClassTemplateSpecializationDecl>(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<CXXRecordDecl>(D)) {
- if (const ClassTemplateSpecializationDecl *Spec
+ if (const ClassTemplateSpecializationDecl *spec
= dyn_cast<ClassTemplateSpecializationDecl>(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<ExprWithCleanups>(E))
+ E = Cleanups->getSubExpr();
+
+ return isa<MaterializeTemporaryExpr>(E);
+}
+
VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const {
if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo())
return cast<VarDecl>(MSI->getInstantiatedFrom());
@@ -2320,8 +2361,15 @@ void RecordDecl::LoadFieldsFromExternalStorage() const {
ExternalASTSource::Deserializing TheFields(Source);
llvm::SmallVector<Decl*, 64> Decls;
- if (Source->FindExternalLexicalDeclsBy<FieldDecl>(this, Decls))
+ LoadedFieldsFromExternalStorage = true;
+ switch (Source->FindExternalLexicalDeclsBy<FieldDecl>(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<FieldDecl>(Decls[i]));
#endif
- LoadedFieldsFromExternalStorage = true;
-
if (Decls.empty())
return;
@@ -2376,6 +2422,16 @@ void BlockDecl::setCaptures(ASTContext &Context,
Captures = static_cast<Capture*>(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 <algorithm>
-#include <cstdio>
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<BlockDecl>(DC)) {
- DC = cast<BlockDecl>(DC)->getDeclContext();
- continue;
- }
- } while (false);
+ while (isa<BlockDecl>(DC))
+ DC = cast<BlockDecl>(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<Decl*, 64> 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<CXXRecordDecl>(
- VBaseTypeInfo->getType()->getAs<RecordType>()->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<NSConsumesSelfAttr>();
+
+ // '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<NonTypeTemplateParmDecl>(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<CXXMethodDecl>(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<MaterializeTemporaryExpr>(SubExpr))
+ SubExpr = Materialize->GetTemporaryExpr();
+
// Skip any temporary bindings; they're implicit.
if (CXXBindTemporaryExpr *Binder = dyn_cast<CXXBindTemporaryExpr>(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<ObjCMessageExpr>(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<WarnUnusedResultAttr>()) {
Loc = getExprLoc();
@@ -1584,6 +1661,9 @@ bool Expr::isOBJCGCCandidate(ASTContext &Ctx) const {
return cast<UnaryOperator>(E)->getSubExpr()->isOBJCGCCandidate(Ctx);
case ImplicitCastExprClass:
return cast<ImplicitCastExpr>(E)->getSubExpr()->isOBJCGCCandidate(Ctx);
+ case MaterializeTemporaryExprClass:
+ return cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr()
+ ->isOBJCGCCandidate(Ctx);
case CStyleCastExprClass:
return cast<CStyleCastExpr>(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<MaterializeTemporaryExpr>(E)) {
+ E = Materialize->GetTemporaryExpr();
+ continue;
+ }
+
return E;
}
}
@@ -1967,6 +2054,10 @@ Expr *Expr::IgnoreParenLValueCasts() {
E = P->getResultExpr();
continue;
}
+ } else if (MaterializeTemporaryExpr *Materialize
+ = dyn_cast<MaterializeTemporaryExpr>(E)) {
+ E = Materialize->GetTemporaryExpr();
+ continue;
}
break;
}
@@ -1996,13 +2087,18 @@ Expr *Expr::IgnoreParenImpCasts() {
continue;
}
}
+ if (MaterializeTemporaryExpr *Materialize
+ = dyn_cast<MaterializeTemporaryExpr>(E)) {
+ E = Materialize->GetTemporaryExpr();
+ continue;
+ }
return E;
}
}
Expr *Expr::IgnoreConversionOperator() {
if (CXXMemberCallExpr *MCE = dyn_cast<CXXMemberCallExpr>(this)) {
- if (isa<CXXConversionDecl>(MCE->getMethodDecl()))
+ if (MCE->getMethodDecl() && isa<CXXConversionDecl>(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<MaterializeTemporaryExpr>(E))
+ E = M->GetTemporaryExpr();
+
while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(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<MaterializeTemporaryExpr>(E))
+ E = M->GetTemporaryExpr();
+
while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
if (ICE->getCastKind() == CK_NoOp)
E = ICE->getSubExpr();
@@ -2155,6 +2257,12 @@ bool Expr::isImplicitCXXThis() const {
}
}
+ if (const MaterializeTemporaryExpr *M
+ = dyn_cast<MaterializeTemporaryExpr>(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<MaterializeTemporaryExpr>(this)->GetTemporaryExpr()
+ ->isConstantInitializer(Ctx, false);
}
return isEvaluatable(Ctx);
}
@@ -2345,6 +2457,9 @@ Expr::isNullPointerConstant(ASTContext &Ctx,
} else if (isa<GNUNullExpr>(this)) {
// The GNU __null extension is always a null pointer constant.
return NPCK_GNUNull;
+ } else if (const MaterializeTemporaryExpr *M
+ = dyn_cast<MaterializeTemporaryExpr>(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<BinaryOperator>(E))
+ if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(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<uintptr_t>(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<uintptr_t>(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<uintptr_t>(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<IdentifierInfo *>(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<ExprWithCleanups>(e))
e = ewc->getSubExpr();
+ if (const MaterializeTemporaryExpr *m = dyn_cast<MaterializeTemporaryExpr>(e))
+ e = m->GetTemporaryExpr();
e = cast<CXXConstructExpr>(e)->getArg(0);
while (const ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(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<ExplicitTemplateArgumentList*>(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<SubstNonTypeTemplateParmExpr>(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<ExplicitCastExpr>(E)->getTypeAsWritten());
+ case Expr::CXXUnresolvedConstructExprClass:
+ return ClassifyUnnamed(Ctx,
+ cast<CXXUnresolvedConstructExpr>(E)->getTypeAsWritten());
+
case Expr::BinaryConditionalOperatorClass: {
if (!Lang.CPlusPlus) return Cl::CL_PRValue;
const BinaryConditionalOperator *co = cast<BinaryConditionalOperator>(E);
@@ -339,6 +347,11 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::PackExpansionExprClass:
return ClassifyInternal(Ctx, cast<PackExpansionExpr>(E)->getPattern());
+
+ case Expr::MaterializeTemporaryExprClass:
+ return cast<MaterializeTemporaryExpr>(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<EnumConstantDecl>(D))
- return Success(ECD->getInitVal(), E);
+ if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(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<SubstNonTypeTemplateParmExpr>(E)->getReplacement(), Ctx);
+
case Expr::ParenExprClass:
return CheckICE(cast<ParenExpr>(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<CastExpr>(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<Decl*> &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<FunctionType>(Context.getASTContext()
- .getCanonicalType(FD->getType()));
-
- mangleBareFunctionType(FT, MangleReturnType);
+ mangleBareFunctionType(FD->getType()->getAs<FunctionType>(),
+ 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) {
- // <unresolved-type> ::= <template-param>
- // ::= <decltype>
- // ::= <template-template-param> <template-args>
- // (this last is not official yet)
-
- if (isa<TemplateTypeParmType>(type)) return true;
- if (isa<DecltypeType>(type)) return true;
- // typeof?
- if (const TemplateSpecializationType *tst =
- dyn_cast<TemplateSpecializationType>(type)) {
- TemplateDecl *temp = tst->getTemplateName().getAsTemplateDecl();
- if (temp && isa<TemplateTemplateParmDecl>(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 T...> class A {
+ // template <class U...> void foo(decltype(T::foo(U())) x...);
+ // };
+ Out << "_SUBSTPACK_";
+ break;
+
+ // <unresolved-type> ::= <template-param>
+ // ::= <decltype>
+ // ::= <template-template-param> <template-args>
+ // (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<TypedefType>(type)->getDecl()->getIdentifier());
+ break;
+
+ case Type::UnresolvedUsing:
+ mangleSourceName(cast<UnresolvedUsingType>(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<RecordType>(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<TemplateSpecializationType>(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<TemplateTemplateParmDecl>(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 <template <class U> class T...> class A {
+ // template <class U...> void foo(decltype(T<U>::foo) x...);
+ // };
+ Out << "_SUBSTPACK_";
+ break;
+ }
+ }
- // Only certain other types are valid as prefixes; enumerate them.
- // FIXME: can we get ElaboratedTypes here?
- // FIXME: SubstTemplateTypeParmType?
- if (const TagType *t = dyn_cast<TagType>(type)) {
- mangleSourceName(t->getDecl()->getIdentifier());
- } else if (const TypedefType *t = dyn_cast<TypedefType>(type)) {
- mangleSourceName(t->getDecl()->getIdentifier());
- } else if (const UnresolvedUsingType *t
- = dyn_cast<UnresolvedUsingType>(type)) {
- mangleSourceName(t->getDecl()->getIdentifier());
- } else if (const DependentNameType *t
- = dyn_cast<DependentNameType>(type)) {
- mangleSourceName(t->getIdentifier());
- } else if (const TemplateSpecializationType *tst
- = dyn_cast<TemplateSpecializationType>(type)) {
- TemplateDecl *temp = tst->getTemplateName().getAsTemplateDecl();
- assert(temp && "no template for template specialization type");
- mangleSourceName(temp->getIdentifier());
mangleUnresolvedTemplateArgs(tst->getArgs(), tst->getNumArgs());
- } else if (const DependentTemplateSpecializationType *tst
- = dyn_cast<DependentTemplateSpecializationType>(type)) {
+ break;
+ }
+
+ case Type::InjectedClassName:
+ mangleSourceName(cast<InjectedClassNameType>(type)->getDecl()
+ ->getIdentifier());
+ break;
+
+ case Type::DependentName:
+ mangleSourceName(cast<DependentNameType>(type)->getIdentifier());
+ break;
+
+ case Type::DependentTemplateSpecialization: {
+ const DependentTemplateSpecializationType *tst
+ = cast<DependentTemplateSpecializationType>(type);
mangleSourceName(tst->getIdentifier());
mangleUnresolvedTemplateArgs(tst->getArgs(), tst->getNumArgs());
- } else {
- llvm_unreachable("unexpected type in nested name specifier!");
+ break;
+ }
}
break;
}
@@ -1036,7 +1097,7 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
case DeclarationName::CXXConversionFunctionName:
// <operator-name> ::= cv <type> # (cast)
Out << "cv";
- mangleType(Context.getASTContext().getCanonicalType(Name.getCXXNameType()));
+ mangleType(Name.getCXXNameType());
break;
case DeclarationName::CXXOperatorName: {
@@ -1323,10 +1384,23 @@ void CXXNameMangler::mangleType(TemplateName TN) {
break;
}
+ case TemplateName::SubstTemplateTemplateParm: {
+ // Substituted template parameters are mangled as the substituted
+ // template. This will check for the substitution twice, which is
+ // fine, but we have to return early so that we don't try to *add*
+ // the substitution twice.
+ SubstTemplateTemplateParmStorage *subst
+ = TN.getAsSubstTemplateTemplateParm();
+ mangleType(subst->getReplacement());
+ return;
+ }
+
case TemplateName::SubstTemplateTemplateParmPack: {
- SubstTemplateTemplateParmPackStorage *SubstPack
- = TN.getAsSubstTemplateTemplateParmPack();
- mangleTemplateParameter(SubstPack->getParameterPack()->getIndex());
+ // FIXME: not clear how to mangle this!
+ // template <template <class> class T...> class A {
+ // template <template <class> class U...> void foo(B<T,U> x...);
+ // };
+ Out << "_SUBSTPACK_";
break;
}
}
@@ -1464,7 +1538,40 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals) {
Out << 'U' << ASString.size() << ASString;
}
- // FIXME: For now, just drop all extension qualifiers on the floor.
+ llvm::StringRef LifetimeName;
+ switch (Quals.getObjCLifetime()) {
+ // Objective-C ARC Extension:
+ //
+ // <type> ::= U "__strong"
+ // <type> ::= U "__weak"
+ // <type> ::= U "__autoreleasing"
+ case Qualifiers::OCL_None:
+ break;
+
+ case Qualifiers::OCL_Weak:
+ LifetimeName = "__weak";
+ break;
+
+ case Qualifiers::OCL_Strong:
+ LifetimeName = "__strong";
+ break;
+
+ case Qualifiers::OCL_Autoreleasing:
+ LifetimeName = "__autoreleasing";
+ break;
+
+ case Qualifiers::OCL_ExplicitNone:
+ // The __unsafe_unretained qualifier is *not* mangled, so that
+ // __unsafe_unretained types in ARC produce the same manglings as the
+ // equivalent (but, naturally, unqualified) types in non-ARC, providing
+ // better ABI compatibility.
+ //
+ // It's safe to do this because unqualified 'id' won't show up
+ // in any type signatures that need to be mangled.
+ break;
+ }
+ if (!LifetimeName.empty())
+ Out << 'U' << LifetimeName.size() << LifetimeName;
}
void CXXNameMangler::mangleRefQualifier(RefQualifierKind RefQualifier) {
@@ -1489,26 +1596,59 @@ void CXXNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) {
Context.mangleObjCMethodName(MD, Out);
}
-void CXXNameMangler::mangleType(QualType nonCanon) {
- // Only operate on the canonical type!
- QualType canon = nonCanon.getCanonicalType();
-
- SplitQualType split = canon.split();
+void CXXNameMangler::mangleType(QualType T) {
+ // If our type is instantiation-dependent but not dependent, we mangle
+ // it as it was written in the source, removing any top-level sugar.
+ // Otherwise, use the canonical type.
+ //
+ // FIXME: This is an approximation of the instantiation-dependent name
+ // mangling rules, since we should really be using the type as written and
+ // augmented via semantic analysis (i.e., with implicit conversions and
+ // default template arguments) for any instantiation-dependent type.
+ // Unfortunately, that requires several changes to our AST:
+ // - Instantiation-dependent TemplateSpecializationTypes will need to be
+ // uniqued, so that we can handle substitutions properly
+ // - Default template arguments will need to be represented in the
+ // TemplateSpecializationType, since they need to be mangled even though
+ // they aren't written.
+ // - Conversions on non-type template arguments need to be expressed, since
+ // they can affect the mangling of sizeof/alignof.
+ if (!T->isInstantiationDependentType() || T->isDependentType())
+ T = T.getCanonicalType();
+ else {
+ // Desugar any types that are purely sugar.
+ do {
+ // Don't desugar through template specialization types that aren't
+ // type aliases. We need to mangle the template arguments as written.
+ if (const TemplateSpecializationType *TST
+ = dyn_cast<TemplateSpecializationType>(T))
+ if (!TST->isTypeAlias())
+ break;
+
+ QualType Desugared
+ = T.getSingleStepDesugaredType(Context.getASTContext());
+ if (Desugared == T)
+ break;
+
+ T = Desugared;
+ } while (true);
+ }
+ SplitQualType split = T.split();
Qualifiers quals = split.second;
const Type *ty = split.first;
- bool isSubstitutable = quals || !isa<BuiltinType>(ty);
- if (isSubstitutable && mangleSubstitution(canon))
+ bool isSubstitutable = quals || !isa<BuiltinType>(T);
+ if (isSubstitutable && mangleSubstitution(T))
return;
// If we're mangling a qualified array type, push the qualifiers to
// the element type.
- if (quals && isa<ArrayType>(ty)) {
- ty = Context.getASTContext().getAsArrayType(canon);
+ if (quals && isa<ArrayType>(T)) {
+ ty = Context.getASTContext().getAsArrayType(T);
quals = Qualifiers();
- // Note that we don't update canon: we want to add the
- // substitution at the canonical type.
+ // Note that we don't update T: we want to add the
+ // substitution at the original type.
}
if (quals) {
@@ -1533,7 +1673,7 @@ void CXXNameMangler::mangleType(QualType nonCanon) {
// Add the substitution.
if (isSubstitutable)
- addSubstitution(canon);
+ addSubstitution(T);
}
void CXXNameMangler::mangleNameOrStandardSubstitution(const NamedDecl *ND) {
@@ -1647,7 +1787,7 @@ void CXXNameMangler::mangleBareFunctionType(const FunctionType *T,
for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(),
ArgEnd = Proto->arg_type_end();
Arg != ArgEnd; ++Arg)
- mangleType(*Arg);
+ mangleType(Context.getASTContext().getSignatureParameterType(*Arg));
FunctionTypeDepth.pop(saved);
@@ -1737,7 +1877,11 @@ void CXXNameMangler::mangleType(const TemplateTypeParmType *T) {
// <type> ::= <template-param>
void CXXNameMangler::mangleType(const SubstTemplateTypeParmPackType *T) {
- mangleTemplateParameter(T->getReplacedParameter()->getIndex());
+ // FIXME: not clear how to mangle this!
+ // template <class T...> class A {
+ // template <class U...> void foo(T(*)(U) x...);
+ // };
+ Out << "_SUBSTPACK_";
}
// <type> ::= P <type> # pointer-to
@@ -2052,6 +2196,9 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
// <expr-primary> ::= L <type> <value number> E # integer literal
// ::= L <type <value float> E # floating literal
// ::= L <mangled-name> E # external name
+ QualType ImplicitlyConvertedToType;
+
+recurse:
switch (E->getStmtClass()) {
case Expr::NoStmtClass:
#define ABSTRACT_STMT(Type)
@@ -2089,6 +2236,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
case Expr::ObjCProtocolExprClass:
case Expr::ObjCSelectorExprClass:
case Expr::ObjCStringLiteralClass:
+ case Expr::ObjCIndirectCopyRestoreExprClass:
case Expr::OffsetOfExprClass:
case Expr::PredefinedExprClass:
case Expr::ShuffleVectorExprClass:
@@ -2131,6 +2279,11 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
mangleExpression(cast<CXXDefaultArgExpr>(E)->getExpr(), Arity);
break;
+ case Expr::SubstNonTypeTemplateParmExprClass:
+ mangleExpression(cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement(),
+ Arity);
+ break;
+
case Expr::CXXMemberCallExprClass: // fallthrough
case Expr::CallExprClass: {
const CallExpr *CE = cast<CallExpr>(E);
@@ -2209,6 +2362,10 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
case Expr::UnresolvedLookupExprClass: {
const UnresolvedLookupExpr *ULE = cast<UnresolvedLookupExpr>(E);
mangleUnresolvedName(ULE->getQualifier(), 0, ULE->getName(), Arity);
+
+ // All the <unresolved-name> productions end in a
+ // base-unresolved-name, where <template-args> are just tacked
+ // onto the end.
if (ULE->hasExplicitTemplateArgs())
mangleTemplateArgs(ULE->getExplicitTemplateArgs());
break;
@@ -2241,6 +2398,23 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
case Expr::UnaryExprOrTypeTraitExprClass: {
const UnaryExprOrTypeTraitExpr *SAE = cast<UnaryExprOrTypeTraitExpr>(E);
+
+ if (!SAE->isInstantiationDependent()) {
+ // Itanium C++ ABI:
+ // If the operand of a sizeof or alignof operator is not
+ // instantiation-dependent it is encoded as an integer literal
+ // reflecting the result of the operator.
+ //
+ // If the result of the operator is implicitly converted to a known
+ // integer type, that type is used for the literal; otherwise, the type
+ // of std::size_t or std::ptrdiff_t is used.
+ QualType T = (ImplicitlyConvertedToType.isNull() ||
+ !ImplicitlyConvertedToType->isIntegerType())? SAE->getType()
+ : ImplicitlyConvertedToType;
+ mangleIntegerLiteral(T, SAE->EvaluateAsInt(Context.getASTContext()));
+ break;
+ }
+
switch(SAE->getKind()) {
case UETT_SizeOf:
Out << 's';
@@ -2344,10 +2518,19 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
}
case Expr::ImplicitCastExprClass: {
- mangleExpression(cast<ImplicitCastExpr>(E)->getSubExpr(), Arity);
- break;
+ ImplicitlyConvertedToType = E->getType();
+ E = cast<ImplicitCastExpr>(E)->getSubExpr();
+ goto recurse;
}
-
+
+ case Expr::ObjCBridgedCastExprClass: {
+ // Mangle ownership casts as a vendor extended operator __bridge,
+ // __bridge_transfer, or __bridge_retain.
+ llvm::StringRef Kind = cast<ObjCBridgedCastExpr>(E)->getBridgeKindName();
+ Out << "v1U" << Kind.size() << Kind;
+ }
+ // Fall through to mangle the cast itself.
+
case Expr::CStyleCastExprClass:
case Expr::CXXStaticCastExprClass:
case Expr::CXXDynamicCastExprClass:
@@ -2408,35 +2591,22 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
}
case Expr::SubstNonTypeTemplateParmPackExprClass:
- mangleTemplateParameter(
- cast<SubstNonTypeTemplateParmPackExpr>(E)->getParameterPack()->getIndex());
+ // FIXME: not clear how to mangle this!
+ // template <unsigned N...> class A {
+ // template <class U...> void foo(U (&x)[N]...);
+ // };
+ Out << "_SUBSTPACK_";
break;
case Expr::DependentScopeDeclRefExprClass: {
const DependentScopeDeclRefExpr *DRE = cast<DependentScopeDeclRefExpr>(E);
- NestedNameSpecifier *NNS = DRE->getQualifier();
- const Type *QTy = NNS->getAsType();
-
- // When we're dealing with a nested-name-specifier that has just a
- // dependent identifier in it, mangle that as a typename. FIXME:
- // It isn't clear that we ever actually want to have such a
- // nested-name-specifier; why not just represent it as a typename type?
- if (!QTy && NNS->getAsIdentifier() && NNS->getPrefix()) {
- QTy = getASTContext().getDependentNameType(ETK_Typename,
- NNS->getPrefix(),
- NNS->getAsIdentifier())
- .getTypePtr();
- }
- assert(QTy && "Qualifier was not type!");
+ mangleUnresolvedName(DRE->getQualifier(), 0, DRE->getDeclName(), Arity);
- // ::= sr <type> <unqualified-name> # dependent name
- // ::= sr <type> <unqualified-name> <template-args> # dependent template-id
- Out << "sr";
- mangleType(QualType(QTy, 0));
- mangleUnqualifiedName(0, DRE->getDeclName(), Arity);
+ // All the <unresolved-name> productions end in a
+ // base-unresolved-name, where <template-args> are just tacked
+ // onto the end.
if (DRE->hasExplicitTemplateArgs())
mangleTemplateArgs(DRE->getExplicitTemplateArgs());
-
break;
}
@@ -2537,15 +2707,13 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
else if (const TemplateTemplateParmDecl *TempTP
= dyn_cast<TemplateTemplateParmDecl>(Pack))
mangleTemplateParameter(TempTP->getIndex());
- else {
- // Note: proposed by Mike Herrick on 11/30/10
- // <expression> ::= sZ <function-param> # size of function parameter pack
- Diagnostic &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Error,
- "cannot mangle sizeof...(function parameter pack)");
- Diags.Report(DiagID);
- return;
- }
+ else
+ mangleFunctionParam(cast<ParmVarDecl>(Pack));
+ break;
+ }
+
+ case Expr::MaterializeTemporaryExprClass: {
+ mangleExpression(cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr());
break;
}
}
@@ -2696,12 +2864,15 @@ void CXXNameMangler::mangleTemplateArgs(const TemplateParameterList &PL,
}
void CXXNameMangler::mangleTemplateArg(const NamedDecl *P,
- const TemplateArgument &A) {
+ TemplateArgument A) {
// <template-arg> ::= <type> # type or template
// ::= X <expression> E # expression
// ::= <expr-primary> # simple expressions
// ::= J <template-arg>* E # argument pack
- // ::= sp <expression> # pack expansion of (C++0x)
+ // ::= sp <expression> # pack expansion of (C++0x)
+ if (!A.isInstantiationDependent() || A.isDependent())
+ A = Context.getASTContext().getCanonicalTemplateArgument(A);
+
switch (A.getKind()) {
case TemplateArgument::Null:
llvm_unreachable("Cannot mangle NULL template argument");
@@ -2780,6 +2951,18 @@ void CXXNameMangler::mangleTemplateParameter(unsigned Index) {
Out << 'T' << (Index - 1) << '_';
}
+void CXXNameMangler::mangleExistingSubstitution(QualType type) {
+ bool result = mangleSubstitution(type);
+ assert(result && "no existing substitution for type");
+ (void) result;
+}
+
+void CXXNameMangler::mangleExistingSubstitution(TemplateName tname) {
+ bool result = mangleSubstitution(tname);
+ assert(result && "no existing substitution for template name");
+ (void) result;
+}
+
// <substitution> ::= S <seq-id> _
// ::= S_
bool CXXNameMangler::mangleSubstitution(const NamedDecl *ND) {
diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp
index 2878dff3edc4..f6d4f2513ce4 100644
--- a/lib/AST/NestedNameSpecifier.cpp
+++ b/lib/AST/NestedNameSpecifier.cpp
@@ -174,6 +174,28 @@ bool NestedNameSpecifier::isDependent() const {
return false;
}
+/// \brief Whether this nested name specifier refers to a dependent
+/// type or not.
+bool NestedNameSpecifier::isInstantiationDependent() const {
+ switch (getKind()) {
+ case Identifier:
+ // Identifier specifiers always represent dependent types
+ return true;
+
+ case Namespace:
+ case NamespaceAlias:
+ case Global:
+ return false;
+
+ case TypeSpec:
+ case TypeSpecWithTemplate:
+ return getAsType()->isInstantiationDependentType();
+ }
+
+ // Necessary to suppress a GCC warning.
+ return false;
+}
+
bool NestedNameSpecifier::containsUnexpandedParameterPack() const {
switch (getKind()) {
case Identifier:
diff --git a/lib/AST/ParentMap.cpp b/lib/AST/ParentMap.cpp
index eca351aec8dd..b7b2005e9f84 100644
--- a/lib/AST/ParentMap.cpp
+++ b/lib/AST/ParentMap.cpp
@@ -66,6 +66,15 @@ Stmt *ParentMap::getParentIgnoreParenCasts(Stmt *S) const {
return S;
}
+Stmt *ParentMap::getOuterParenParent(Stmt *S) const {
+ Stmt *Paren = 0;
+ while (isa<ParenExpr>(S)) {
+ Paren = S;
+ S = getParent(S);
+ };
+ return Paren;
+}
+
bool ParentMap::isConsumedExpr(Expr* E) const {
Stmt *P = getParent(E);
Stmt *DirectChild = E;
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index de0b1d0ed9db..5636a6f0f64a 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -1242,12 +1242,11 @@ void RecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D) {
}
InitializeLayout(D);
-
+ ObjCInterfaceDecl *OI = const_cast<ObjCInterfaceDecl*>(D);
// Layout each ivar sequentially.
- llvm::SmallVector<ObjCIvarDecl*, 16> Ivars;
- Context.ShallowCollectObjCIvars(D, Ivars);
- for (unsigned i = 0, e = Ivars.size(); i != e; ++i)
- LayoutField(Ivars[i]);
+ for (ObjCIvarDecl *IVD = OI->all_declared_ivar_begin();
+ IVD; IVD = IVD->getNextIvar())
+ LayoutField(IVD);
// Finally, round the size of the total struct up to the alignment of the
// struct itself.
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index 380ad94ca224..fd6f21d43b59 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -20,7 +20,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
-#include <cstdio>
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
static struct StmtClassNameTable {
@@ -54,23 +54,24 @@ void Stmt::PrintStats() {
getStmtInfoTableEntry(Stmt::NullStmtClass);
unsigned sum = 0;
- fprintf(stderr, "*** Stmt/Expr Stats:\n");
+ llvm::errs() << "\n*** Stmt/Expr Stats:\n";
for (int i = 0; i != Stmt::lastStmtConstant+1; i++) {
if (StmtClassInfo[i].Name == 0) continue;
sum += StmtClassInfo[i].Counter;
}
- fprintf(stderr, " %d stmts/exprs total.\n", sum);
+ llvm::errs() << " " << sum << " stmts/exprs total.\n";
sum = 0;
for (int i = 0; i != Stmt::lastStmtConstant+1; i++) {
if (StmtClassInfo[i].Name == 0) continue;
if (StmtClassInfo[i].Counter == 0) continue;
- fprintf(stderr, " %d %s, %d each (%d bytes)\n",
- StmtClassInfo[i].Counter, StmtClassInfo[i].Name,
- StmtClassInfo[i].Size,
- StmtClassInfo[i].Counter*StmtClassInfo[i].Size);
+ llvm::errs() << " " << StmtClassInfo[i].Counter << " "
+ << StmtClassInfo[i].Name << ", " << StmtClassInfo[i].Size
+ << " each (" << StmtClassInfo[i].Counter*StmtClassInfo[i].Size
+ << " bytes)\n";
sum += StmtClassInfo[i].Counter*StmtClassInfo[i].Size;
}
- fprintf(stderr, "Total bytes = %d\n", sum);
+
+ llvm::errs() << "Total bytes = " << sum << "\n";
}
void Stmt::addStmtClass(StmtClass s) {
@@ -84,6 +85,18 @@ bool Stmt::CollectingStats(bool Enable) {
return StatSwitch;
}
+Stmt *Stmt::IgnoreImplicit() {
+ Stmt *s = this;
+
+ if (ExprWithCleanups *ewc = dyn_cast<ExprWithCleanups>(s))
+ s = ewc->getSubExpr();
+
+ while (ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(s))
+ s = ice->getSubExpr();
+
+ return s;
+}
+
namespace {
struct good {};
struct bad {};
@@ -365,6 +378,10 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece>&Pieces,
// Handle %x4 and %x[foo] by capturing x as the modifier character.
char Modifier = '\0';
if (isalpha(EscapedChar)) {
+ if (CurPtr == StrEnd) { // Premature end.
+ DiagOffs = CurPtr-StrStart-1;
+ return diag::err_asm_invalid_escape;
+ }
Modifier = EscapedChar;
EscapedChar = *CurPtr++;
}
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 87588e451884..f705a84c7cf4 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -449,6 +449,12 @@ void StmtPrinter::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *Node) {
OS << "\n";
}
+void StmtPrinter::VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *Node) {
+ Indent() << "@autoreleasepool";
+ PrintRawCompoundStmt(dyn_cast<CompoundStmt>(Node->getSubStmt()));
+ OS << "\n";
+}
+
void StmtPrinter::PrintRawCXXCatchStmt(CXXCatchStmt *Node) {
OS << "catch (";
if (Decl *ExDecl = Node->getExceptionDecl())
@@ -1407,6 +1413,15 @@ void StmtPrinter::VisitSubstNonTypeTemplateParmPackExpr(
OS << Node->getParameterPack()->getNameAsString();
}
+void StmtPrinter::VisitSubstNonTypeTemplateParmExpr(
+ SubstNonTypeTemplateParmExpr *Node) {
+ Visit(Node->getReplacement());
+}
+
+void StmtPrinter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *Node){
+ PrintExpr(Node->GetTemporaryExpr());
+}
+
// Obj-C
void StmtPrinter::VisitObjCStringLiteral(ObjCStringLiteral *Node) {
@@ -1464,6 +1479,17 @@ void StmtPrinter::VisitObjCMessageExpr(ObjCMessageExpr *Mess) {
OS << "]";
}
+void
+StmtPrinter::VisitObjCIndirectCopyRestoreExpr(ObjCIndirectCopyRestoreExpr *E) {
+ PrintExpr(E->getSubExpr());
+}
+
+void
+StmtPrinter::VisitObjCBridgedCastExpr(ObjCBridgedCastExpr *E) {
+ OS << "(" << E->getBridgeKindName() << E->getType().getAsString(Policy)
+ << ")";
+ PrintExpr(E->getSubExpr());
+}
void StmtPrinter::VisitBlockExpr(BlockExpr *Node) {
BlockDecl *BD = Node->getBlockDecl();
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index b117cd9a525f..120c9e50a92a 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -23,7 +23,7 @@
using namespace clang;
namespace {
- class StmtProfiler : public StmtVisitor<StmtProfiler> {
+ class StmtProfiler : public ConstStmtVisitor<StmtProfiler> {
llvm::FoldingSetNodeID &ID;
const ASTContext &Context;
bool Canonical;
@@ -33,14 +33,14 @@ namespace {
bool Canonical)
: ID(ID), Context(Context), Canonical(Canonical) { }
- void VisitStmt(Stmt *S);
+ void VisitStmt(const Stmt *S);
-#define STMT(Node, Base) void Visit##Node(Node *S);
+#define STMT(Node, Base) void Visit##Node(const Node *S);
#include "clang/AST/StmtNodes.inc"
/// \brief Visit a declaration that is referenced within an expression
/// or statement.
- void VisitDecl(Decl *D);
+ void VisitDecl(const Decl *D);
/// \brief Visit a type that is referenced within an expression or
/// statement.
@@ -59,96 +59,97 @@ namespace {
/// \brief Visit template arguments that occur within an expression or
/// statement.
- void VisitTemplateArguments(const TemplateArgumentLoc *Args, unsigned NumArgs);
+ void VisitTemplateArguments(const TemplateArgumentLoc *Args,
+ unsigned NumArgs);
/// \brief Visit a single template argument.
void VisitTemplateArgument(const TemplateArgument &Arg);
};
}
-void StmtProfiler::VisitStmt(Stmt *S) {
+void StmtProfiler::VisitStmt(const Stmt *S) {
ID.AddInteger(S->getStmtClass());
- for (Stmt::child_range C = S->children(); C; ++C)
+ for (Stmt::const_child_range C = S->children(); C; ++C)
Visit(*C);
}
-void StmtProfiler::VisitDeclStmt(DeclStmt *S) {
+void StmtProfiler::VisitDeclStmt(const DeclStmt *S) {
VisitStmt(S);
- for (DeclStmt::decl_iterator D = S->decl_begin(), DEnd = S->decl_end();
+ for (DeclStmt::const_decl_iterator D = S->decl_begin(), DEnd = S->decl_end();
D != DEnd; ++D)
VisitDecl(*D);
}
-void StmtProfiler::VisitNullStmt(NullStmt *S) {
+void StmtProfiler::VisitNullStmt(const NullStmt *S) {
VisitStmt(S);
}
-void StmtProfiler::VisitCompoundStmt(CompoundStmt *S) {
+void StmtProfiler::VisitCompoundStmt(const CompoundStmt *S) {
VisitStmt(S);
}
-void StmtProfiler::VisitSwitchCase(SwitchCase *S) {
+void StmtProfiler::VisitSwitchCase(const SwitchCase *S) {
VisitStmt(S);
}
-void StmtProfiler::VisitCaseStmt(CaseStmt *S) {
+void StmtProfiler::VisitCaseStmt(const CaseStmt *S) {
VisitStmt(S);
}
-void StmtProfiler::VisitDefaultStmt(DefaultStmt *S) {
+void StmtProfiler::VisitDefaultStmt(const DefaultStmt *S) {
VisitStmt(S);
}
-void StmtProfiler::VisitLabelStmt(LabelStmt *S) {
+void StmtProfiler::VisitLabelStmt(const LabelStmt *S) {
VisitStmt(S);
VisitDecl(S->getDecl());
}
-void StmtProfiler::VisitIfStmt(IfStmt *S) {
+void StmtProfiler::VisitIfStmt(const IfStmt *S) {
VisitStmt(S);
VisitDecl(S->getConditionVariable());
}
-void StmtProfiler::VisitSwitchStmt(SwitchStmt *S) {
+void StmtProfiler::VisitSwitchStmt(const SwitchStmt *S) {
VisitStmt(S);
VisitDecl(S->getConditionVariable());
}
-void StmtProfiler::VisitWhileStmt(WhileStmt *S) {
+void StmtProfiler::VisitWhileStmt(const WhileStmt *S) {
VisitStmt(S);
VisitDecl(S->getConditionVariable());
}
-void StmtProfiler::VisitDoStmt(DoStmt *S) {
+void StmtProfiler::VisitDoStmt(const DoStmt *S) {
VisitStmt(S);
}
-void StmtProfiler::VisitForStmt(ForStmt *S) {
+void StmtProfiler::VisitForStmt(const ForStmt *S) {
VisitStmt(S);
}
-void StmtProfiler::VisitGotoStmt(GotoStmt *S) {
+void StmtProfiler::VisitGotoStmt(const GotoStmt *S) {
VisitStmt(S);
VisitDecl(S->getLabel());
}
-void StmtProfiler::VisitIndirectGotoStmt(IndirectGotoStmt *S) {
+void StmtProfiler::VisitIndirectGotoStmt(const IndirectGotoStmt *S) {
VisitStmt(S);
}
-void StmtProfiler::VisitContinueStmt(ContinueStmt *S) {
+void StmtProfiler::VisitContinueStmt(const ContinueStmt *S) {
VisitStmt(S);
}
-void StmtProfiler::VisitBreakStmt(BreakStmt *S) {
+void StmtProfiler::VisitBreakStmt(const BreakStmt *S) {
VisitStmt(S);
}
-void StmtProfiler::VisitReturnStmt(ReturnStmt *S) {
+void StmtProfiler::VisitReturnStmt(const ReturnStmt *S) {
VisitStmt(S);
}
-void StmtProfiler::VisitAsmStmt(AsmStmt *S) {
+void StmtProfiler::VisitAsmStmt(const AsmStmt *S) {
VisitStmt(S);
ID.AddBoolean(S->isVolatile());
ID.AddBoolean(S->isSimple());
@@ -168,63 +169,69 @@ void StmtProfiler::VisitAsmStmt(AsmStmt *S) {
VisitStringLiteral(S->getClobber(I));
}
-void StmtProfiler::VisitCXXCatchStmt(CXXCatchStmt *S) {
+void StmtProfiler::VisitCXXCatchStmt(const CXXCatchStmt *S) {
VisitStmt(S);
VisitType(S->getCaughtType());
}
-void StmtProfiler::VisitCXXTryStmt(CXXTryStmt *S) {
+void StmtProfiler::VisitCXXTryStmt(const CXXTryStmt *S) {
VisitStmt(S);
}
-void StmtProfiler::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
+void StmtProfiler::VisitCXXForRangeStmt(const CXXForRangeStmt *S) {
VisitStmt(S);
}
-void StmtProfiler::VisitSEHTryStmt(SEHTryStmt *S) {
+void StmtProfiler::VisitSEHTryStmt(const SEHTryStmt *S) {
VisitStmt(S);
}
-void StmtProfiler::VisitSEHFinallyStmt(SEHFinallyStmt *S) {
+void StmtProfiler::VisitSEHFinallyStmt(const SEHFinallyStmt *S) {
VisitStmt(S);
}
-void StmtProfiler::VisitSEHExceptStmt(SEHExceptStmt *S) {
+void StmtProfiler::VisitSEHExceptStmt(const SEHExceptStmt *S) {
VisitStmt(S);
}
-void StmtProfiler::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
+void StmtProfiler::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S) {
VisitStmt(S);
}
-void StmtProfiler::VisitObjCAtCatchStmt(ObjCAtCatchStmt *S) {
+void StmtProfiler::VisitObjCAtCatchStmt(const ObjCAtCatchStmt *S) {
VisitStmt(S);
ID.AddBoolean(S->hasEllipsis());
if (S->getCatchParamDecl())
VisitType(S->getCatchParamDecl()->getType());
}
-void StmtProfiler::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *S) {
+void StmtProfiler::VisitObjCAtFinallyStmt(const ObjCAtFinallyStmt *S) {
VisitStmt(S);
}
-void StmtProfiler::VisitObjCAtTryStmt(ObjCAtTryStmt *S) {
+void StmtProfiler::VisitObjCAtTryStmt(const ObjCAtTryStmt *S) {
VisitStmt(S);
}
-void StmtProfiler::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
+void
+StmtProfiler::VisitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt *S) {
VisitStmt(S);
}
-void StmtProfiler::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) {
+void StmtProfiler::VisitObjCAtThrowStmt(const ObjCAtThrowStmt *S) {
VisitStmt(S);
}
-void StmtProfiler::VisitExpr(Expr *S) {
+void
+StmtProfiler::VisitObjCAutoreleasePoolStmt(const ObjCAutoreleasePoolStmt *S) {
VisitStmt(S);
}
-void StmtProfiler::VisitDeclRefExpr(DeclRefExpr *S) {
+void StmtProfiler::VisitExpr(const Expr *S) {
+ VisitStmt(S);
+}
+
+void StmtProfiler::VisitDeclRefExpr(const DeclRefExpr *S) {
VisitExpr(S);
if (!Canonical)
VisitNestedNameSpecifier(S->getQualifier());
@@ -233,52 +240,52 @@ void StmtProfiler::VisitDeclRefExpr(DeclRefExpr *S) {
VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs());
}
-void StmtProfiler::VisitPredefinedExpr(PredefinedExpr *S) {
+void StmtProfiler::VisitPredefinedExpr(const PredefinedExpr *S) {
VisitExpr(S);
ID.AddInteger(S->getIdentType());
}
-void StmtProfiler::VisitIntegerLiteral(IntegerLiteral *S) {
+void StmtProfiler::VisitIntegerLiteral(const IntegerLiteral *S) {
VisitExpr(S);
S->getValue().Profile(ID);
}
-void StmtProfiler::VisitCharacterLiteral(CharacterLiteral *S) {
+void StmtProfiler::VisitCharacterLiteral(const CharacterLiteral *S) {
VisitExpr(S);
ID.AddBoolean(S->isWide());
ID.AddInteger(S->getValue());
}
-void StmtProfiler::VisitFloatingLiteral(FloatingLiteral *S) {
+void StmtProfiler::VisitFloatingLiteral(const FloatingLiteral *S) {
VisitExpr(S);
S->getValue().Profile(ID);
ID.AddBoolean(S->isExact());
}
-void StmtProfiler::VisitImaginaryLiteral(ImaginaryLiteral *S) {
+void StmtProfiler::VisitImaginaryLiteral(const ImaginaryLiteral *S) {
VisitExpr(S);
}
-void StmtProfiler::VisitStringLiteral(StringLiteral *S) {
+void StmtProfiler::VisitStringLiteral(const StringLiteral *S) {
VisitExpr(S);
ID.AddString(S->getString());
ID.AddBoolean(S->isWide());
}
-void StmtProfiler::VisitParenExpr(ParenExpr *S) {
+void StmtProfiler::VisitParenExpr(const ParenExpr *S) {
VisitExpr(S);
}
-void StmtProfiler::VisitParenListExpr(ParenListExpr *S) {
+void StmtProfiler::VisitParenListExpr(const ParenListExpr *S) {
VisitExpr(S);
}
-void StmtProfiler::VisitUnaryOperator(UnaryOperator *S) {
+void StmtProfiler::VisitUnaryOperator(const UnaryOperator *S) {
VisitExpr(S);
ID.AddInteger(S->getOpcode());
}
-void StmtProfiler::VisitOffsetOfExpr(OffsetOfExpr *S) {
+void StmtProfiler::VisitOffsetOfExpr(const OffsetOfExpr *S) {
VisitType(S->getTypeSourceInfo()->getType());
unsigned n = S->getNumComponents();
for (unsigned i = 0; i < n; ++i) {
@@ -306,22 +313,23 @@ void StmtProfiler::VisitOffsetOfExpr(OffsetOfExpr *S) {
VisitExpr(S);
}
-void StmtProfiler::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *S) {
+void
+StmtProfiler::VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *S) {
VisitExpr(S);
ID.AddInteger(S->getKind());
if (S->isArgumentType())
VisitType(S->getArgumentType());
}
-void StmtProfiler::VisitArraySubscriptExpr(ArraySubscriptExpr *S) {
+void StmtProfiler::VisitArraySubscriptExpr(const ArraySubscriptExpr *S) {
VisitExpr(S);
}
-void StmtProfiler::VisitCallExpr(CallExpr *S) {
+void StmtProfiler::VisitCallExpr(const CallExpr *S) {
VisitExpr(S);
}
-void StmtProfiler::VisitMemberExpr(MemberExpr *S) {
+void StmtProfiler::VisitMemberExpr(const MemberExpr *S) {
VisitExpr(S);
VisitDecl(S->getMemberDecl());
if (!Canonical)
@@ -329,72 +337,74 @@ void StmtProfiler::VisitMemberExpr(MemberExpr *S) {
ID.AddBoolean(S->isArrow());
}
-void StmtProfiler::VisitCompoundLiteralExpr(CompoundLiteralExpr *S) {
+void StmtProfiler::VisitCompoundLiteralExpr(const CompoundLiteralExpr *S) {
VisitExpr(S);
ID.AddBoolean(S->isFileScope());
}
-void StmtProfiler::VisitCastExpr(CastExpr *S) {
+void StmtProfiler::VisitCastExpr(const CastExpr *S) {
VisitExpr(S);
}
-void StmtProfiler::VisitImplicitCastExpr(ImplicitCastExpr *S) {
+void StmtProfiler::VisitImplicitCastExpr(const ImplicitCastExpr *S) {
VisitCastExpr(S);
ID.AddInteger(S->getValueKind());
}
-void StmtProfiler::VisitExplicitCastExpr(ExplicitCastExpr *S) {
+void StmtProfiler::VisitExplicitCastExpr(const ExplicitCastExpr *S) {
VisitCastExpr(S);
VisitType(S->getTypeAsWritten());
}
-void StmtProfiler::VisitCStyleCastExpr(CStyleCastExpr *S) {
+void StmtProfiler::VisitCStyleCastExpr(const CStyleCastExpr *S) {
VisitExplicitCastExpr(S);
}
-void StmtProfiler::VisitBinaryOperator(BinaryOperator *S) {
+void StmtProfiler::VisitBinaryOperator(const BinaryOperator *S) {
VisitExpr(S);
ID.AddInteger(S->getOpcode());
}
-void StmtProfiler::VisitCompoundAssignOperator(CompoundAssignOperator *S) {
+void
+StmtProfiler::VisitCompoundAssignOperator(const CompoundAssignOperator *S) {
VisitBinaryOperator(S);
}
-void StmtProfiler::VisitConditionalOperator(ConditionalOperator *S) {
+void StmtProfiler::VisitConditionalOperator(const ConditionalOperator *S) {
VisitExpr(S);
}
-void StmtProfiler::VisitBinaryConditionalOperator(BinaryConditionalOperator *S){
+void StmtProfiler::VisitBinaryConditionalOperator(
+ const BinaryConditionalOperator *S) {
VisitExpr(S);
}
-void StmtProfiler::VisitAddrLabelExpr(AddrLabelExpr *S) {
+void StmtProfiler::VisitAddrLabelExpr(const AddrLabelExpr *S) {
VisitExpr(S);
VisitDecl(S->getLabel());
}
-void StmtProfiler::VisitStmtExpr(StmtExpr *S) {
+void StmtProfiler::VisitStmtExpr(const StmtExpr *S) {
VisitExpr(S);
}
-void StmtProfiler::VisitShuffleVectorExpr(ShuffleVectorExpr *S) {
+void StmtProfiler::VisitShuffleVectorExpr(const ShuffleVectorExpr *S) {
VisitExpr(S);
}
-void StmtProfiler::VisitChooseExpr(ChooseExpr *S) {
+void StmtProfiler::VisitChooseExpr(const ChooseExpr *S) {
VisitExpr(S);
}
-void StmtProfiler::VisitGNUNullExpr(GNUNullExpr *S) {
+void StmtProfiler::VisitGNUNullExpr(const GNUNullExpr *S) {
VisitExpr(S);
}
-void StmtProfiler::VisitVAArgExpr(VAArgExpr *S) {
+void StmtProfiler::VisitVAArgExpr(const VAArgExpr *S) {
VisitExpr(S);
}
-void StmtProfiler::VisitInitListExpr(InitListExpr *S) {
+void StmtProfiler::VisitInitListExpr(const InitListExpr *S) {
if (S->getSyntacticForm()) {
VisitInitListExpr(S->getSyntacticForm());
return;
@@ -403,11 +413,11 @@ void StmtProfiler::VisitInitListExpr(InitListExpr *S) {
VisitExpr(S);
}
-void StmtProfiler::VisitDesignatedInitExpr(DesignatedInitExpr *S) {
+void StmtProfiler::VisitDesignatedInitExpr(const DesignatedInitExpr *S) {
VisitExpr(S);
ID.AddBoolean(S->usesGNUSyntax());
- for (DesignatedInitExpr::designators_iterator D = S->designators_begin(),
- DEnd = S->designators_end();
+ for (DesignatedInitExpr::const_designators_iterator D =
+ S->designators_begin(), DEnd = S->designators_end();
D != DEnd; ++D) {
if (D->isFieldDesignator()) {
ID.AddInteger(0);
@@ -425,28 +435,28 @@ void StmtProfiler::VisitDesignatedInitExpr(DesignatedInitExpr *S) {
}
}
-void StmtProfiler::VisitImplicitValueInitExpr(ImplicitValueInitExpr *S) {
+void StmtProfiler::VisitImplicitValueInitExpr(const ImplicitValueInitExpr *S) {
VisitExpr(S);
}
-void StmtProfiler::VisitExtVectorElementExpr(ExtVectorElementExpr *S) {
+void StmtProfiler::VisitExtVectorElementExpr(const ExtVectorElementExpr *S) {
VisitExpr(S);
VisitName(&S->getAccessor());
}
-void StmtProfiler::VisitBlockExpr(BlockExpr *S) {
+void StmtProfiler::VisitBlockExpr(const BlockExpr *S) {
VisitExpr(S);
VisitDecl(S->getBlockDecl());
}
-void StmtProfiler::VisitBlockDeclRefExpr(BlockDeclRefExpr *S) {
+void StmtProfiler::VisitBlockDeclRefExpr(const BlockDeclRefExpr *S) {
VisitExpr(S);
VisitDecl(S->getDecl());
ID.AddBoolean(S->isByRef());
ID.AddBoolean(S->isConstQualAdded());
}
-void StmtProfiler::VisitGenericSelectionExpr(GenericSelectionExpr *S) {
+void StmtProfiler::VisitGenericSelectionExpr(const GenericSelectionExpr *S) {
VisitExpr(S);
for (unsigned i = 0; i != S->getNumAssocs(); ++i) {
QualType T = S->getAssocType(i);
@@ -458,7 +468,7 @@ void StmtProfiler::VisitGenericSelectionExpr(GenericSelectionExpr *S) {
}
}
-static Stmt::StmtClass DecodeOperatorCall(CXXOperatorCallExpr *S,
+static Stmt::StmtClass DecodeOperatorCall(const CXXOperatorCallExpr *S,
UnaryOperatorKind &UnaryOp,
BinaryOperatorKind &BinaryOp) {
switch (S->getOperator()) {
@@ -645,7 +655,7 @@ static Stmt::StmtClass DecodeOperatorCall(CXXOperatorCallExpr *S,
}
-void StmtProfiler::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *S) {
+void StmtProfiler::VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *S) {
if (S->isTypeDependent()) {
// Type-dependent operator calls are profiled like their underlying
// syntactic operator.
@@ -671,97 +681,100 @@ void StmtProfiler::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *S) {
ID.AddInteger(S->getOperator());
}
-void StmtProfiler::VisitCXXMemberCallExpr(CXXMemberCallExpr *S) {
+void StmtProfiler::VisitCXXMemberCallExpr(const CXXMemberCallExpr *S) {
VisitCallExpr(S);
}
-void StmtProfiler::VisitCUDAKernelCallExpr(CUDAKernelCallExpr *S) {
+void StmtProfiler::VisitCUDAKernelCallExpr(const CUDAKernelCallExpr *S) {
VisitCallExpr(S);
}
-void StmtProfiler::VisitAsTypeExpr(AsTypeExpr *S) {
+void StmtProfiler::VisitAsTypeExpr(const AsTypeExpr *S) {
VisitExpr(S);
}
-void StmtProfiler::VisitCXXNamedCastExpr(CXXNamedCastExpr *S) {
+void StmtProfiler::VisitCXXNamedCastExpr(const CXXNamedCastExpr *S) {
VisitExplicitCastExpr(S);
}
-void StmtProfiler::VisitCXXStaticCastExpr(CXXStaticCastExpr *S) {
+void StmtProfiler::VisitCXXStaticCastExpr(const CXXStaticCastExpr *S) {
VisitCXXNamedCastExpr(S);
}
-void StmtProfiler::VisitCXXDynamicCastExpr(CXXDynamicCastExpr *S) {
+void StmtProfiler::VisitCXXDynamicCastExpr(const CXXDynamicCastExpr *S) {
VisitCXXNamedCastExpr(S);
}
-void StmtProfiler::VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *S) {
+void
+StmtProfiler::VisitCXXReinterpretCastExpr(const CXXReinterpretCastExpr *S) {
VisitCXXNamedCastExpr(S);
}
-void StmtProfiler::VisitCXXConstCastExpr(CXXConstCastExpr *S) {
+void StmtProfiler::VisitCXXConstCastExpr(const CXXConstCastExpr *S) {
VisitCXXNamedCastExpr(S);
}
-void StmtProfiler::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *S) {
+void StmtProfiler::VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *S) {
VisitExpr(S);
ID.AddBoolean(S->getValue());
}
-void StmtProfiler::VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *S) {
+void StmtProfiler::VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *S) {
VisitExpr(S);
}
-void StmtProfiler::VisitCXXTypeidExpr(CXXTypeidExpr *S) {
+void StmtProfiler::VisitCXXTypeidExpr(const CXXTypeidExpr *S) {
VisitExpr(S);
if (S->isTypeOperand())
VisitType(S->getTypeOperand());
}
-void StmtProfiler::VisitCXXUuidofExpr(CXXUuidofExpr *S) {
+void StmtProfiler::VisitCXXUuidofExpr(const CXXUuidofExpr *S) {
VisitExpr(S);
if (S->isTypeOperand())
VisitType(S->getTypeOperand());
}
-void StmtProfiler::VisitCXXThisExpr(CXXThisExpr *S) {
+void StmtProfiler::VisitCXXThisExpr(const CXXThisExpr *S) {
VisitExpr(S);
}
-void StmtProfiler::VisitCXXThrowExpr(CXXThrowExpr *S) {
+void StmtProfiler::VisitCXXThrowExpr(const CXXThrowExpr *S) {
VisitExpr(S);
}
-void StmtProfiler::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *S) {
+void StmtProfiler::VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *S) {
VisitExpr(S);
VisitDecl(S->getParam());
}
-void StmtProfiler::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *S) {
+void StmtProfiler::VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *S) {
VisitExpr(S);
VisitDecl(
const_cast<CXXDestructorDecl *>(S->getTemporary()->getDestructor()));
}
-void StmtProfiler::VisitCXXConstructExpr(CXXConstructExpr *S) {
+void StmtProfiler::VisitCXXConstructExpr(const CXXConstructExpr *S) {
VisitExpr(S);
VisitDecl(S->getConstructor());
ID.AddBoolean(S->isElidable());
}
-void StmtProfiler::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *S) {
+void StmtProfiler::VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *S) {
VisitExplicitCastExpr(S);
}
-void StmtProfiler::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *S) {
+void
+StmtProfiler::VisitCXXTemporaryObjectExpr(const CXXTemporaryObjectExpr *S) {
VisitCXXConstructExpr(S);
}
-void StmtProfiler::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *S) {
+void
+StmtProfiler::VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *S) {
VisitExpr(S);
}
-void StmtProfiler::VisitCXXDeleteExpr(CXXDeleteExpr *S) {
+void StmtProfiler::VisitCXXDeleteExpr(const CXXDeleteExpr *S) {
VisitExpr(S);
ID.AddBoolean(S->isGlobalDelete());
ID.AddBoolean(S->isArrayForm());
@@ -769,7 +782,7 @@ void StmtProfiler::VisitCXXDeleteExpr(CXXDeleteExpr *S) {
}
-void StmtProfiler::VisitCXXNewExpr(CXXNewExpr *S) {
+void StmtProfiler::VisitCXXNewExpr(const CXXNewExpr *S) {
VisitExpr(S);
VisitType(S->getAllocatedType());
VisitDecl(S->getOperatorNew());
@@ -783,14 +796,15 @@ void StmtProfiler::VisitCXXNewExpr(CXXNewExpr *S) {
ID.AddInteger(S->getNumConstructorArgs());
}
-void StmtProfiler::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *S) {
+void
+StmtProfiler::VisitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *S) {
VisitExpr(S);
ID.AddBoolean(S->isArrow());
VisitNestedNameSpecifier(S->getQualifier());
VisitType(S->getDestroyedType());
}
-void StmtProfiler::VisitOverloadExpr(OverloadExpr *S) {
+void StmtProfiler::VisitOverloadExpr(const OverloadExpr *S) {
VisitExpr(S);
VisitNestedNameSpecifier(S->getQualifier());
VisitName(S->getName());
@@ -801,37 +815,37 @@ void StmtProfiler::VisitOverloadExpr(OverloadExpr *S) {
}
void
-StmtProfiler::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *S) {
+StmtProfiler::VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *S) {
VisitOverloadExpr(S);
}
-void StmtProfiler::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *S) {
+void StmtProfiler::VisitUnaryTypeTraitExpr(const UnaryTypeTraitExpr *S) {
VisitExpr(S);
ID.AddInteger(S->getTrait());
VisitType(S->getQueriedType());
}
-void StmtProfiler::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *S) {
+void StmtProfiler::VisitBinaryTypeTraitExpr(const BinaryTypeTraitExpr *S) {
VisitExpr(S);
ID.AddInteger(S->getTrait());
VisitType(S->getLhsType());
VisitType(S->getRhsType());
}
-void StmtProfiler::VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *S) {
+void StmtProfiler::VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *S) {
VisitExpr(S);
ID.AddInteger(S->getTrait());
VisitType(S->getQueriedType());
}
-void StmtProfiler::VisitExpressionTraitExpr(ExpressionTraitExpr *S) {
+void StmtProfiler::VisitExpressionTraitExpr(const ExpressionTraitExpr *S) {
VisitExpr(S);
ID.AddInteger(S->getTrait());
VisitExpr(S->getQueriedExpression());
}
-void
-StmtProfiler::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *S) {
+void StmtProfiler::VisitDependentScopeDeclRefExpr(
+ const DependentScopeDeclRefExpr *S) {
VisitExpr(S);
VisitName(S->getDeclName());
VisitNestedNameSpecifier(S->getQualifier());
@@ -840,18 +854,18 @@ StmtProfiler::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *S) {
VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs());
}
-void StmtProfiler::VisitExprWithCleanups(ExprWithCleanups *S) {
+void StmtProfiler::VisitExprWithCleanups(const ExprWithCleanups *S) {
VisitExpr(S);
}
-void
-StmtProfiler::VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *S) {
+void StmtProfiler::VisitCXXUnresolvedConstructExpr(
+ const CXXUnresolvedConstructExpr *S) {
VisitExpr(S);
VisitType(S->getTypeAsWritten());
}
-void
-StmtProfiler::VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *S) {
+void StmtProfiler::VisitCXXDependentScopeMemberExpr(
+ const CXXDependentScopeMemberExpr *S) {
ID.AddBoolean(S->isImplicitAccess());
if (!S->isImplicitAccess()) {
VisitExpr(S);
@@ -864,7 +878,7 @@ StmtProfiler::VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *S) {
VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs());
}
-void StmtProfiler::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *S) {
+void StmtProfiler::VisitUnresolvedMemberExpr(const UnresolvedMemberExpr *S) {
ID.AddBoolean(S->isImplicitAccess());
if (!S->isImplicitAccess()) {
VisitExpr(S);
@@ -877,57 +891,68 @@ void StmtProfiler::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *S) {
VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs());
}
-void StmtProfiler::VisitCXXNoexceptExpr(CXXNoexceptExpr *S) {
+void StmtProfiler::VisitCXXNoexceptExpr(const CXXNoexceptExpr *S) {
VisitExpr(S);
}
-void StmtProfiler::VisitPackExpansionExpr(PackExpansionExpr *S) {
+void StmtProfiler::VisitPackExpansionExpr(const PackExpansionExpr *S) {
VisitExpr(S);
}
-void StmtProfiler::VisitSizeOfPackExpr(SizeOfPackExpr *S) {
+void StmtProfiler::VisitSizeOfPackExpr(const SizeOfPackExpr *S) {
VisitExpr(S);
VisitDecl(S->getPack());
}
void StmtProfiler::VisitSubstNonTypeTemplateParmPackExpr(
- SubstNonTypeTemplateParmPackExpr *S) {
+ const SubstNonTypeTemplateParmPackExpr *S) {
VisitExpr(S);
VisitDecl(S->getParameterPack());
VisitTemplateArgument(S->getArgumentPack());
}
-void StmtProfiler::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
+void StmtProfiler::VisitSubstNonTypeTemplateParmExpr(
+ const SubstNonTypeTemplateParmExpr *E) {
+ // Profile exactly as the replacement expression.
+ Visit(E->getReplacement());
+}
+
+void StmtProfiler::VisitMaterializeTemporaryExpr(
+ const MaterializeTemporaryExpr *S) {
+ VisitExpr(S);
+}
+
+void StmtProfiler::VisitOpaqueValueExpr(const OpaqueValueExpr *E) {
VisitExpr(E);
}
-void StmtProfiler::VisitObjCStringLiteral(ObjCStringLiteral *S) {
+void StmtProfiler::VisitObjCStringLiteral(const ObjCStringLiteral *S) {
VisitExpr(S);
}
-void StmtProfiler::VisitObjCEncodeExpr(ObjCEncodeExpr *S) {
+void StmtProfiler::VisitObjCEncodeExpr(const ObjCEncodeExpr *S) {
VisitExpr(S);
VisitType(S->getEncodedType());
}
-void StmtProfiler::VisitObjCSelectorExpr(ObjCSelectorExpr *S) {
+void StmtProfiler::VisitObjCSelectorExpr(const ObjCSelectorExpr *S) {
VisitExpr(S);
VisitName(S->getSelector());
}
-void StmtProfiler::VisitObjCProtocolExpr(ObjCProtocolExpr *S) {
+void StmtProfiler::VisitObjCProtocolExpr(const ObjCProtocolExpr *S) {
VisitExpr(S);
VisitDecl(S->getProtocol());
}
-void StmtProfiler::VisitObjCIvarRefExpr(ObjCIvarRefExpr *S) {
+void StmtProfiler::VisitObjCIvarRefExpr(const ObjCIvarRefExpr *S) {
VisitExpr(S);
VisitDecl(S->getDecl());
ID.AddBoolean(S->isArrow());
ID.AddBoolean(S->isFreeIvar());
}
-void StmtProfiler::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *S) {
+void StmtProfiler::VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *S) {
VisitExpr(S);
if (S->isImplicitProperty()) {
VisitDecl(S->getImplicitPropertyGetter());
@@ -941,22 +966,34 @@ void StmtProfiler::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *S) {
}
}
-void StmtProfiler::VisitObjCMessageExpr(ObjCMessageExpr *S) {
+void StmtProfiler::VisitObjCMessageExpr(const ObjCMessageExpr *S) {
VisitExpr(S);
VisitName(S->getSelector());
VisitDecl(S->getMethodDecl());
}
-void StmtProfiler::VisitObjCIsaExpr(ObjCIsaExpr *S) {
+void StmtProfiler::VisitObjCIsaExpr(const ObjCIsaExpr *S) {
VisitExpr(S);
ID.AddBoolean(S->isArrow());
}
-void StmtProfiler::VisitDecl(Decl *D) {
+void StmtProfiler::VisitObjCIndirectCopyRestoreExpr(
+ const ObjCIndirectCopyRestoreExpr *S) {
+ VisitExpr(S);
+ ID.AddBoolean(S->shouldCopy());
+}
+
+void StmtProfiler::VisitObjCBridgedCastExpr(const ObjCBridgedCastExpr *S) {
+ VisitExplicitCastExpr(S);
+ ID.AddBoolean(S->getBridgeKind());
+}
+
+void StmtProfiler::VisitDecl(const Decl *D) {
ID.AddInteger(D? D->getKind() : 0);
if (Canonical && D) {
- if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) {
+ if (const NonTypeTemplateParmDecl *NTTP =
+ dyn_cast<NonTypeTemplateParmDecl>(D)) {
ID.AddInteger(NTTP->getDepth());
ID.AddInteger(NTTP->getIndex());
ID.AddBoolean(NTTP->isParameterPack());
@@ -964,7 +1001,7 @@ void StmtProfiler::VisitDecl(Decl *D) {
return;
}
- if (ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D)) {
+ if (const ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D)) {
// The Itanium C++ ABI uses the type, scope depth, and scope
// index of a parameter when mangling expressions that involve
// function parameters, so we will use the parameter's type for
@@ -978,7 +1015,8 @@ void StmtProfiler::VisitDecl(Decl *D) {
return;
}
- if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(D)) {
+ if (const TemplateTemplateParmDecl *TTP =
+ dyn_cast<TemplateTemplateParmDecl>(D)) {
ID.AddInteger(TTP->getDepth());
ID.AddInteger(TTP->getIndex());
ID.AddBoolean(TTP->isParameterPack());
@@ -1058,7 +1096,7 @@ void StmtProfiler::VisitTemplateArgument(const TemplateArgument &Arg) {
}
void Stmt::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
- bool Canonical) {
+ bool Canonical) const {
StmtProfiler Profiler(ID, Context, Canonical);
Profiler.Visit(this);
}
diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp
index 6114a5a051be..56c6e7bc47c1 100644
--- a/lib/AST/TemplateBase.cpp
+++ b/lib/AST/TemplateBase.cpp
@@ -104,6 +104,45 @@ bool TemplateArgument::isDependent() const {
return false;
}
+bool TemplateArgument::isInstantiationDependent() const {
+ switch (getKind()) {
+ case Null:
+ assert(false && "Should not have a NULL template argument");
+ return false;
+
+ case Type:
+ return getAsType()->isInstantiationDependentType();
+
+ case Template:
+ return getAsTemplate().isInstantiationDependent();
+
+ case TemplateExpansion:
+ return true;
+
+ case Declaration:
+ if (DeclContext *DC = dyn_cast<DeclContext>(getAsDecl()))
+ return DC->isDependentContext();
+ return getAsDecl()->getDeclContext()->isDependentContext();
+
+ case Integral:
+ // Never dependent
+ return false;
+
+ case Expression:
+ return getAsExpr()->isInstantiationDependent();
+
+ case Pack:
+ for (pack_iterator P = pack_begin(), PEnd = pack_end(); P != PEnd; ++P) {
+ if (P->isInstantiationDependent())
+ return true;
+ }
+
+ return false;
+ }
+
+ return false;
+}
+
bool TemplateArgument::isPackExpansion() const {
switch (getKind()) {
case Null:
@@ -277,8 +316,10 @@ void TemplateArgument::print(const PrintingPolicy &Policy,
break;
case Type: {
+ PrintingPolicy SubPolicy(Policy);
+ SubPolicy.SuppressStrongLifetime = true;
std::string TypeStr;
- getAsType().getAsStringInternal(TypeStr, Policy);
+ getAsType().getAsStringInternal(TypeStr, SubPolicy);
Out << TypeStr;
break;
}
diff --git a/lib/AST/TemplateName.cpp b/lib/AST/TemplateName.cpp
index ebd07f486783..1f7b19aae471 100644
--- a/lib/AST/TemplateName.cpp
+++ b/lib/AST/TemplateName.cpp
@@ -27,7 +27,19 @@ SubstTemplateTemplateParmPackStorage::getArgumentPack() const {
return TemplateArgument(Arguments, size());
}
-void SubstTemplateTemplateParmPackStorage::Profile(llvm::FoldingSetNodeID &ID) {
+void SubstTemplateTemplateParmStorage::Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, Parameter, Replacement);
+}
+
+void SubstTemplateTemplateParmStorage::Profile(llvm::FoldingSetNodeID &ID,
+ TemplateTemplateParmDecl *parameter,
+ TemplateName replacement) {
+ ID.AddPointer(parameter);
+ ID.AddPointer(replacement.getAsVoidPointer());
+}
+
+void SubstTemplateTemplateParmPackStorage::Profile(llvm::FoldingSetNodeID &ID,
+ ASTContext &Context) {
Profile(ID, Context, Parameter, TemplateArgument(Arguments, size()));
}
@@ -46,9 +58,14 @@ TemplateName::NameKind TemplateName::getKind() const {
return DependentTemplate;
if (Storage.is<QualifiedTemplateName *>())
return QualifiedTemplate;
-
- return getAsOverloadedTemplate()? OverloadedTemplate
- : SubstTemplateTemplateParmPack;
+
+ UncommonTemplateNameStorage *uncommon
+ = Storage.get<UncommonTemplateNameStorage*>();
+ if (uncommon->getAsOverloadedStorage())
+ return OverloadedTemplate;
+ if (uncommon->getAsSubstTemplateTemplateParm())
+ return SubstTemplateTemplateParm;
+ return SubstTemplateTemplateParmPack;
}
TemplateDecl *TemplateName::getAsTemplateDecl() const {
@@ -58,6 +75,9 @@ TemplateDecl *TemplateName::getAsTemplateDecl() const {
if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName())
return QTN->getTemplateDecl();
+ if (SubstTemplateTemplateParmStorage *sub = getAsSubstTemplateTemplateParm())
+ return sub->getReplacement().getAsTemplateDecl();
+
return 0;
}
@@ -79,6 +99,15 @@ bool TemplateName::isDependent() const {
return true;
}
+bool TemplateName::isInstantiationDependent() const {
+ if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) {
+ if (QTN->getQualifier()->isInstantiationDependent())
+ return true;
+ }
+
+ return isDependent();
+}
+
bool TemplateName::containsUnexpandedParameterPack() const {
if (TemplateDecl *Template = getAsTemplateDecl()) {
if (TemplateTemplateParmDecl *TTP
@@ -115,6 +144,9 @@ TemplateName::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy,
OS << DTN->getIdentifier()->getName();
else
OS << "operator " << getOperatorSpelling(DTN->getOperator());
+ } else if (SubstTemplateTemplateParmStorage *subst
+ = getAsSubstTemplateTemplateParm()) {
+ subst->getReplacement().print(OS, Policy, SuppressNNS);
} else if (SubstTemplateTemplateParmPackStorage *SubstPack
= getAsSubstTemplateTemplateParmPack())
OS << SubstPack->getParameterPack()->getNameAsString();
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index d28755284477..08971eb03421 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -36,7 +36,10 @@ bool Qualifiers::isStrictSupersetOf(Qualifiers Other) const {
(hasObjCGCAttr() && !Other.hasObjCGCAttr())) &&
// Address space superset.
((getAddressSpace() == Other.getAddressSpace()) ||
- (hasAddressSpace()&& !Other.hasAddressSpace()));
+ (hasAddressSpace()&& !Other.hasAddressSpace())) &&
+ // Lifetime qualifier superset.
+ ((getObjCLifetime() == Other.getObjCLifetime()) ||
+ (hasObjCLifetime() && !Other.hasObjCLifetime()));
}
bool QualType::isConstant(QualType T, ASTContext &Ctx) {
@@ -107,6 +110,7 @@ DependentSizedExtVectorType::DependentSizedExtVectorType(const
Expr *SizeExpr,
SourceLocation loc)
: Type(DependentSizedExtVector, can, /*Dependent=*/true,
+ /*InstantiationDependent=*/true,
ElementType->isVariablyModifiedType(),
(ElementType->containsUnexpandedParameterPack() ||
(SizeExpr && SizeExpr->containsUnexpandedParameterPack()))),
@@ -126,6 +130,7 @@ DependentSizedExtVectorType::Profile(llvm::FoldingSetNodeID &ID,
VectorType::VectorType(QualType vecType, unsigned nElements, QualType canonType,
VectorKind vecKind)
: Type(Vector, canonType, vecType->isDependentType(),
+ vecType->isInstantiationDependentType(),
vecType->isVariablyModifiedType(),
vecType->containsUnexpandedParameterPack()),
ElementType(vecType)
@@ -137,6 +142,7 @@ VectorType::VectorType(QualType vecType, unsigned nElements, QualType canonType,
VectorType::VectorType(TypeClass tc, QualType vecType, unsigned nElements,
QualType canonType, VectorKind vecKind)
: Type(tc, canonType, vecType->isDependentType(),
+ vecType->isInstantiationDependentType(),
vecType->isVariablyModifiedType(),
vecType->containsUnexpandedParameterPack()),
ElementType(vecType)
@@ -174,6 +180,26 @@ QualType QualType::getDesugaredType(QualType T, const ASTContext &Context) {
return Context.getQualifiedType(split.first, split.second);
}
+QualType QualType::getSingleStepDesugaredType(const ASTContext &Context) const {
+ QualifierCollector Qs;
+
+ const Type *CurTy = Qs.strip(*this);
+ switch (CurTy->getTypeClass()) {
+#define ABSTRACT_TYPE(Class, Parent)
+#define TYPE(Class, Parent) \
+ case Type::Class: { \
+ const Class##Type *Ty = cast<Class##Type>(CurTy); \
+ if (!Ty->isSugared()) \
+ return *this; \
+ return Context.getQualifiedType(Ty->desugar(), Qs); \
+ break; \
+ }
+#include "clang/AST/TypeNodes.def"
+ }
+
+ return *this;
+}
+
SplitQualType QualType::getSplitDesugaredType(QualType T) {
QualifierCollector Qs;
@@ -285,7 +311,6 @@ bool Type::isDerivedType() const {
return false;
}
}
-
bool Type::isClassType() const {
if (const RecordType *RT = getAs<RecordType>())
return RT->getDecl()->isClass();
@@ -385,7 +410,7 @@ const RecordType *Type::getAsUnionType() const {
ObjCObjectType::ObjCObjectType(QualType Canonical, QualType Base,
ObjCProtocolDecl * const *Protocols,
unsigned NumProtocols)
- : Type(ObjCObject, Canonical, false, false, false),
+ : Type(ObjCObject, Canonical, false, false, false, false),
BaseType(Base)
{
ObjCObjectTypeBits.NumProtocols = NumProtocols;
@@ -866,39 +891,57 @@ bool Type::isIncompleteType() const {
}
}
-/// isPODType - Return true if this is a plain-old-data type (C++ 3.9p10)
-bool Type::isPODType() const {
+bool QualType::isPODType(ASTContext &Context) const {
// The compiler shouldn't query this for incomplete types, but the user might.
// We return false for that case. Except for incomplete arrays of PODs, which
// are PODs according to the standard.
- if (isIncompleteArrayType() &&
- cast<ArrayType>(CanonicalType)->getElementType()->isPODType())
- return true;
- if (isIncompleteType())
+ if (isNull())
+ return 0;
+
+ if ((*this)->isIncompleteArrayType())
+ return Context.getBaseElementType(*this).isPODType(Context);
+
+ if ((*this)->isIncompleteType())
return false;
+ if (Context.getLangOptions().ObjCAutoRefCount) {
+ switch (getObjCLifetime()) {
+ case Qualifiers::OCL_ExplicitNone:
+ return true;
+
+ case Qualifiers::OCL_Strong:
+ case Qualifiers::OCL_Weak:
+ case Qualifiers::OCL_Autoreleasing:
+ return false;
+
+ case Qualifiers::OCL_None:
+ break;
+ }
+ }
+
+ QualType CanonicalType = getTypePtr()->CanonicalType;
switch (CanonicalType->getTypeClass()) {
// Everything not explicitly mentioned is not POD.
default: return false;
- case VariableArray:
- case ConstantArray:
+ case Type::VariableArray:
+ case Type::ConstantArray:
// IncompleteArray is handled above.
- return cast<ArrayType>(CanonicalType)->getElementType()->isPODType();
-
- case Builtin:
- case Complex:
- case Pointer:
- case MemberPointer:
- case Vector:
- case ExtVector:
- case ObjCObjectPointer:
- case BlockPointer:
+ return Context.getBaseElementType(*this).isPODType(Context);
+
+ case Type::ObjCObjectPointer:
+ case Type::BlockPointer:
+ case Type::Builtin:
+ case Type::Complex:
+ case Type::Pointer:
+ case Type::MemberPointer:
+ case Type::Vector:
+ case Type::ExtVector:
return true;
- case Enum:
+ case Type::Enum:
return true;
- case Record:
+ case Type::Record:
if (CXXRecordDecl *ClassDecl
= dyn_cast<CXXRecordDecl>(cast<RecordType>(CanonicalType)->getDecl()))
return ClassDecl->isPOD();
@@ -908,6 +951,121 @@ bool Type::isPODType() const {
}
}
+bool QualType::isTrivialType(ASTContext &Context) const {
+ // The compiler shouldn't query this for incomplete types, but the user might.
+ // We return false for that case. Except for incomplete arrays of PODs, which
+ // are PODs according to the standard.
+ if (isNull())
+ return 0;
+
+ if ((*this)->isArrayType())
+ return Context.getBaseElementType(*this).isTrivialType(Context);
+
+ // Return false for incomplete types after skipping any incomplete array
+ // types which are expressly allowed by the standard and thus our API.
+ if ((*this)->isIncompleteType())
+ return false;
+
+ if (Context.getLangOptions().ObjCAutoRefCount) {
+ switch (getObjCLifetime()) {
+ case Qualifiers::OCL_ExplicitNone:
+ return true;
+
+ case Qualifiers::OCL_Strong:
+ case Qualifiers::OCL_Weak:
+ case Qualifiers::OCL_Autoreleasing:
+ return false;
+
+ case Qualifiers::OCL_None:
+ if ((*this)->isObjCLifetimeType())
+ return false;
+ break;
+ }
+ }
+
+ QualType CanonicalType = getTypePtr()->CanonicalType;
+ if (CanonicalType->isDependentType())
+ return false;
+
+ // C++0x [basic.types]p9:
+ // Scalar types, trivial class types, arrays of such types, and
+ // cv-qualified versions of these types are collectively called trivial
+ // types.
+
+ // As an extension, Clang treats vector types as Scalar types.
+ if (CanonicalType->isScalarType() || CanonicalType->isVectorType())
+ return true;
+ if (const RecordType *RT = CanonicalType->getAs<RecordType>()) {
+ if (const CXXRecordDecl *ClassDecl =
+ dyn_cast<CXXRecordDecl>(RT->getDecl())) {
+ // C++0x [class]p5:
+ // A trivial class is a class that has a trivial default constructor
+ if (!ClassDecl->hasTrivialDefaultConstructor()) return false;
+ // and is trivially copyable.
+ if (!ClassDecl->isTriviallyCopyable()) return false;
+ }
+
+ return true;
+ }
+
+ // No other types can match.
+ return false;
+}
+
+bool QualType::isTriviallyCopyableType(ASTContext &Context) const {
+ if ((*this)->isArrayType())
+ return Context.getBaseElementType(*this).isTrivialType(Context);
+
+ if (Context.getLangOptions().ObjCAutoRefCount) {
+ switch (getObjCLifetime()) {
+ case Qualifiers::OCL_ExplicitNone:
+ return true;
+
+ case Qualifiers::OCL_Strong:
+ case Qualifiers::OCL_Weak:
+ case Qualifiers::OCL_Autoreleasing:
+ return false;
+
+ case Qualifiers::OCL_None:
+ if ((*this)->isObjCLifetimeType())
+ return false;
+ break;
+ }
+ }
+
+ // C++0x [basic.types]p9
+ // Scalar types, trivially copyable class types, arrays of such types, and
+ // cv-qualified versions of these types are collectively called trivial
+ // types.
+
+ QualType CanonicalType = getCanonicalType();
+ if (CanonicalType->isDependentType())
+ return false;
+
+ // Return false for incomplete types after skipping any incomplete array types
+ // which are expressly allowed by the standard and thus our API.
+ if (CanonicalType->isIncompleteType())
+ return false;
+
+ // As an extension, Clang treats vector types as Scalar types.
+ if (CanonicalType->isScalarType() || CanonicalType->isVectorType())
+ return true;
+
+ if (const RecordType *RT = CanonicalType->getAs<RecordType>()) {
+ if (const CXXRecordDecl *ClassDecl =
+ dyn_cast<CXXRecordDecl>(RT->getDecl())) {
+ if (!ClassDecl->isTriviallyCopyable()) return false;
+ }
+
+ return true;
+ }
+
+ // No other types can match.
+ return false;
+}
+
+
+
bool Type::isLiteralType() const {
if (isDependentType())
return false;
@@ -928,6 +1086,10 @@ bool Type::isLiteralType() const {
if (BaseTy->isIncompleteType())
return false;
+ // Objective-C lifetime types are not literal types.
+ if (BaseTy->isObjCRetainableType())
+ return false;
+
// C++0x [basic.types]p10:
// A type is a literal type if it is:
// -- a scalar type; or
@@ -961,68 +1123,6 @@ bool Type::isLiteralType() const {
return false;
}
-bool Type::isTrivialType() const {
- if (isDependentType())
- return false;
-
- // C++0x [basic.types]p9:
- // Scalar types, trivial class types, arrays of such types, and
- // cv-qualified versions of these types are collectively called trivial
- // types.
- const Type *BaseTy = getBaseElementTypeUnsafe();
- assert(BaseTy && "NULL element type");
-
- // Return false for incomplete types after skipping any incomplete array
- // types which are expressly allowed by the standard and thus our API.
- if (BaseTy->isIncompleteType())
- return false;
-
- // As an extension, Clang treats vector types as Scalar types.
- if (BaseTy->isScalarType() || BaseTy->isVectorType()) return true;
- if (const RecordType *RT = BaseTy->getAs<RecordType>()) {
- if (const CXXRecordDecl *ClassDecl =
- dyn_cast<CXXRecordDecl>(RT->getDecl())) {
- if (!ClassDecl->isTrivial()) return false;
- }
-
- return true;
- }
-
- // No other types can match.
- return false;
-}
-
-bool Type::isTriviallyCopyableType() const {
- if (isDependentType())
- return false;
-
- // C++0x [basic.types]p9
- // Scalar types, trivially copyable class types, arrays of such types, and
- // cv-qualified versions of these types are collectively called trivial
- // types.
- const Type *BaseTy = getBaseElementTypeUnsafe();
- assert(BaseTy && "NULL element type");
-
- // Return false for incomplete types after skipping any incomplete array types
- // which are expressly allowed by the standard and thus our API.
- if (BaseTy->isIncompleteType())
- return false;
-
- // As an extension, Clang treats vector types as Scalar types.
- if (BaseTy->isScalarType() || BaseTy->isVectorType()) return true;
- if (const RecordType *RT = BaseTy->getAs<RecordType>()) {
- if (const CXXRecordDecl *ClassDecl =
- dyn_cast<CXXRecordDecl>(RT->getDecl())) {
- if (!ClassDecl->isTriviallyCopyable()) return false;
- }
-
- return true;
- }
-
- // No other types can match.
- return false;
-}
-
bool Type::isStandardLayoutType() const {
if (isDependentType())
return false;
@@ -1060,14 +1160,32 @@ bool Type::isStandardLayoutType() const {
// This is effectively the intersection of isTrivialType and
// isStandardLayoutType. We implement it dircetly to avoid redundant
// conversions from a type to a CXXRecordDecl.
-bool Type::isCXX11PODType() const {
- if (isDependentType())
+bool QualType::isCXX11PODType(ASTContext &Context) const {
+ const Type *ty = getTypePtr();
+ if (ty->isDependentType())
return false;
+ if (Context.getLangOptions().ObjCAutoRefCount) {
+ switch (getObjCLifetime()) {
+ case Qualifiers::OCL_ExplicitNone:
+ return true;
+
+ case Qualifiers::OCL_Strong:
+ case Qualifiers::OCL_Weak:
+ case Qualifiers::OCL_Autoreleasing:
+ return false;
+
+ case Qualifiers::OCL_None:
+ if (ty->isObjCLifetimeType())
+ return false;
+ break;
+ }
+ }
+
// C++11 [basic.types]p9:
// Scalar types, POD classes, arrays of such types, and cv-qualified
// versions of these types are collectively called trivial types.
- const Type *BaseTy = getBaseElementTypeUnsafe();
+ const Type *BaseTy = ty->getBaseElementTypeUnsafe();
assert(BaseTy && "NULL element type");
// Return false for incomplete types after skipping any incomplete array
@@ -1253,7 +1371,7 @@ DependentTemplateSpecializationType::DependentTemplateSpecializationType(
NestedNameSpecifier *NNS, const IdentifierInfo *Name,
unsigned NumArgs, const TemplateArgument *Args,
QualType Canon)
- : TypeWithKeyword(Keyword, DependentTemplateSpecialization, Canon, true,
+ : TypeWithKeyword(Keyword, DependentTemplateSpecialization, Canon, true, true,
/*VariablyModified=*/false,
NNS && NNS->containsUnexpandedParameterPack()),
NNS(NNS), Name(Name), NumArgs(NumArgs) {
@@ -1388,18 +1506,22 @@ FunctionProtoType::FunctionProtoType(QualType result, const QualType *args,
: FunctionType(FunctionProto, result, epi.Variadic, epi.TypeQuals,
epi.RefQualifier, canonical,
result->isDependentType(),
+ result->isInstantiationDependentType(),
result->isVariablyModifiedType(),
result->containsUnexpandedParameterPack(),
epi.ExtInfo),
NumArgs(numArgs), NumExceptions(epi.NumExceptions),
- ExceptionSpecType(epi.ExceptionSpecType)
+ ExceptionSpecType(epi.ExceptionSpecType),
+ HasAnyConsumedArgs(epi.ConsumedArguments != 0)
{
// Fill in the trailing argument array.
QualType *argSlot = reinterpret_cast<QualType*>(this+1);
for (unsigned i = 0; i != numArgs; ++i) {
if (args[i]->isDependentType())
setDependent();
-
+ else if (args[i]->isInstantiationDependentType())
+ setInstantiationDependent();
+
if (args[i]->containsUnexpandedParameterPack())
setContainsUnexpandedParameterPack();
@@ -1412,7 +1534,9 @@ FunctionProtoType::FunctionProtoType(QualType result, const QualType *args,
for (unsigned i = 0, e = epi.NumExceptions; i != e; ++i) {
if (epi.Exceptions[i]->isDependentType())
setDependent();
-
+ else if (epi.Exceptions[i]->isInstantiationDependentType())
+ setInstantiationDependent();
+
if (epi.Exceptions[i]->containsUnexpandedParameterPack())
setContainsUnexpandedParameterPack();
@@ -1422,6 +1546,20 @@ FunctionProtoType::FunctionProtoType(QualType result, const QualType *args,
// Store the noexcept expression and context.
Expr **noexSlot = reinterpret_cast<Expr**>(argSlot + numArgs);
*noexSlot = epi.NoexceptExpr;
+
+ if (epi.NoexceptExpr) {
+ if (epi.NoexceptExpr->isValueDependent()
+ || epi.NoexceptExpr->isTypeDependent())
+ setDependent();
+ else if (epi.NoexceptExpr->isInstantiationDependent())
+ setInstantiationDependent();
+ }
+ }
+
+ if (epi.ConsumedArguments) {
+ bool *consumedArgs = const_cast<bool*>(getConsumedArgsBuffer());
+ for (unsigned i = 0; i != numArgs; ++i)
+ consumedArgs[i] = epi.ConsumedArguments[i];
}
}
@@ -1461,18 +1599,48 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
const QualType *ArgTys, unsigned NumArgs,
const ExtProtoInfo &epi,
const ASTContext &Context) {
+
+ // We have to be careful not to get ambiguous profile encodings.
+ // Note that valid type pointers are never ambiguous with anything else.
+ //
+ // The encoding grammar begins:
+ // type type* bool int bool
+ // If that final bool is true, then there is a section for the EH spec:
+ // bool type*
+ // This is followed by an optional "consumed argument" section of the
+ // same length as the first type sequence:
+ // bool*
+ // Finally, we have the ext info:
+ // int
+ //
+ // There is no ambiguity between the consumed arguments and an empty EH
+ // spec because of the leading 'bool' which unambiguously indicates
+ // whether the following bool is the EH spec or part of the arguments.
+
ID.AddPointer(Result.getAsOpaquePtr());
for (unsigned i = 0; i != NumArgs; ++i)
ID.AddPointer(ArgTys[i].getAsOpaquePtr());
- ID.AddBoolean(epi.Variadic);
- ID.AddInteger(epi.TypeQuals);
- ID.AddInteger(epi.RefQualifier);
- ID.AddInteger(epi.ExceptionSpecType);
+ // This method is relatively performance sensitive, so as a performance
+ // shortcut, use one AddInteger call instead of four for the next four
+ // fields.
+ assert(!(unsigned(epi.Variadic) & ~1) &&
+ !(unsigned(epi.TypeQuals) & ~255) &&
+ !(unsigned(epi.RefQualifier) & ~3) &&
+ !(unsigned(epi.ExceptionSpecType) & ~7) &&
+ "Values larger than expected.");
+ ID.AddInteger(unsigned(epi.Variadic) +
+ (epi.TypeQuals << 1) +
+ (epi.RefQualifier << 9) +
+ (epi.ExceptionSpecType << 11));
if (epi.ExceptionSpecType == EST_Dynamic) {
for (unsigned i = 0; i != epi.NumExceptions; ++i)
ID.AddPointer(epi.Exceptions[i].getAsOpaquePtr());
} else if (epi.ExceptionSpecType == EST_ComputedNoexcept && epi.NoexceptExpr){
- epi.NoexceptExpr->Profile(ID, Context, true);
+ epi.NoexceptExpr->Profile(ID, Context, false);
+ }
+ if (epi.ConsumedArguments) {
+ for (unsigned i = 0; i != NumArgs; ++i)
+ ID.AddBoolean(epi.ConsumedArguments[i]);
}
epi.ExtInfo.Profile(ID);
}
@@ -1489,13 +1657,21 @@ QualType TypedefType::desugar() const {
TypeOfExprType::TypeOfExprType(Expr *E, QualType can)
: Type(TypeOfExpr, can, E->isTypeDependent(),
+ E->isInstantiationDependent(),
E->getType()->isVariablyModifiedType(),
E->containsUnexpandedParameterPack()),
TOExpr(E) {
}
+bool TypeOfExprType::isSugared() const {
+ return !TOExpr->isTypeDependent();
+}
+
QualType TypeOfExprType::desugar() const {
- return getUnderlyingExpr()->getType();
+ if (isSugared())
+ return getUnderlyingExpr()->getType();
+
+ return QualType(this, 0);
}
void DependentTypeOfExprType::Profile(llvm::FoldingSetNodeID &ID,
@@ -1505,12 +1681,22 @@ void DependentTypeOfExprType::Profile(llvm::FoldingSetNodeID &ID,
DecltypeType::DecltypeType(Expr *E, QualType underlyingType, QualType can)
: Type(Decltype, can, E->isTypeDependent(),
+ E->isInstantiationDependent(),
E->getType()->isVariablyModifiedType(),
E->containsUnexpandedParameterPack()),
E(E),
UnderlyingType(underlyingType) {
}
+bool DecltypeType::isSugared() const { return !E->isInstantiationDependent(); }
+
+QualType DecltypeType::desugar() const {
+ if (isSugared())
+ return getUnderlyingType();
+
+ return QualType(this, 0);
+}
+
DependentDecltypeType::DependentDecltypeType(const ASTContext &Context, Expr *E)
: DecltypeType(E, Context.DependentTy), Context(Context) { }
@@ -1520,7 +1706,9 @@ void DependentDecltypeType::Profile(llvm::FoldingSetNodeID &ID,
}
TagType::TagType(TypeClass TC, const TagDecl *D, QualType can)
- : Type(TC, can, D->isDependentType(), /*VariablyModified=*/false,
+ : Type(TC, can, D->isDependentType(),
+ /*InstantiationDependent=*/D->isDependentType(),
+ /*VariablyModified=*/false,
/*ContainsUnexpandedParameterPack=*/false),
decl(const_cast<TagDecl*>(D)) {}
@@ -1540,6 +1728,7 @@ UnaryTransformType::UnaryTransformType(QualType BaseType,
UTTKind UKind,
QualType CanonicalType)
: Type(UnaryTransform, CanonicalType, UnderlyingType->isDependentType(),
+ UnderlyingType->isInstantiationDependentType(),
UnderlyingType->isVariablyModifiedType(),
BaseType->containsUnexpandedParameterPack())
, BaseType(BaseType), UnderlyingType(UnderlyingType), UKind(UKind)
@@ -1573,7 +1762,8 @@ SubstTemplateTypeParmPackType::
SubstTemplateTypeParmPackType(const TemplateTypeParmType *Param,
QualType Canon,
const TemplateArgument &ArgPack)
- : Type(SubstTemplateTypeParmPack, Canon, true, false, true), Replaced(Param),
+ : Type(SubstTemplateTypeParmPack, Canon, true, true, false, true),
+ Replaced(Param),
Arguments(ArgPack.pack_begin()), NumArguments(ArgPack.pack_size())
{
}
@@ -1598,23 +1788,39 @@ void SubstTemplateTypeParmPackType::Profile(llvm::FoldingSetNodeID &ID,
}
bool TemplateSpecializationType::
-anyDependentTemplateArguments(const TemplateArgumentListInfo &Args) {
- return anyDependentTemplateArguments(Args.getArgumentArray(), Args.size());
+anyDependentTemplateArguments(const TemplateArgumentListInfo &Args,
+ bool &InstantiationDependent) {
+ return anyDependentTemplateArguments(Args.getArgumentArray(), Args.size(),
+ InstantiationDependent);
}
bool TemplateSpecializationType::
-anyDependentTemplateArguments(const TemplateArgumentLoc *Args, unsigned N) {
- for (unsigned i = 0; i != N; ++i)
- if (Args[i].getArgument().isDependent())
+anyDependentTemplateArguments(const TemplateArgumentLoc *Args, unsigned N,
+ bool &InstantiationDependent) {
+ for (unsigned i = 0; i != N; ++i) {
+ if (Args[i].getArgument().isDependent()) {
+ InstantiationDependent = true;
return true;
+ }
+
+ if (Args[i].getArgument().isInstantiationDependent())
+ InstantiationDependent = true;
+ }
return false;
}
bool TemplateSpecializationType::
-anyDependentTemplateArguments(const TemplateArgument *Args, unsigned N) {
- for (unsigned i = 0; i != N; ++i)
- if (Args[i].isDependent())
+anyDependentTemplateArguments(const TemplateArgument *Args, unsigned N,
+ bool &InstantiationDependent) {
+ for (unsigned i = 0; i != N; ++i) {
+ if (Args[i].isDependent()) {
+ InstantiationDependent = true;
return true;
+ }
+
+ if (Args[i].isInstantiationDependent())
+ InstantiationDependent = true;
+ }
return false;
}
@@ -1625,12 +1831,22 @@ TemplateSpecializationType(TemplateName T,
: Type(TemplateSpecialization,
Canon.isNull()? QualType(this, 0) : Canon,
Canon.isNull()? T.isDependent() : Canon->isDependentType(),
+ Canon.isNull()? T.isDependent()
+ : Canon->isInstantiationDependentType(),
false, T.containsUnexpandedParameterPack()),
Template(T), NumArgs(NumArgs) {
assert(!T.getAsDependentTemplateName() &&
"Use DependentTemplateSpecializationType for dependent template-name");
+ assert((T.getKind() == TemplateName::Template ||
+ T.getKind() == TemplateName::SubstTemplateTemplateParm ||
+ T.getKind() == TemplateName::SubstTemplateTemplateParmPack) &&
+ "Unexpected template name for TemplateSpecializationType");
+ bool InstantiationDependent;
+ (void)InstantiationDependent;
assert((!Canon.isNull() ||
- T.isDependent() || anyDependentTemplateArguments(Args, NumArgs)) &&
+ T.isDependent() ||
+ anyDependentTemplateArguments(Args, NumArgs,
+ InstantiationDependent)) &&
"No canonical type for non-dependent class template specialization");
TemplateArgument *TemplateArgs
@@ -1644,6 +1860,9 @@ TemplateSpecializationType(TemplateName T,
// U<T> is always non-dependent, irrespective of the type T.
if (Canon.isNull() && Args[Arg].isDependent())
setDependent();
+ else if (Args[Arg].isInstantiationDependent())
+ setInstantiationDependent();
+
if (Args[Arg].getKind() == TemplateArgument::Type &&
Args[Arg].getAsType()->isVariablyModifiedType())
setVariablyModified();
@@ -1795,8 +2014,8 @@ static CachedProperties computeCachedProperties(const Type *T) {
#define DEPENDENT_TYPE(Class,Base) case Type::Class:
#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class,Base) case Type::Class:
#include "clang/AST/TypeNodes.def"
- // Treat dependent types as external.
- assert(T->isDependentType());
+ // Treat instantiation-dependent types as external.
+ assert(T->isInstantiationDependentType());
return CachedProperties(ExternalLinkage, DefaultVisibility, false);
case Type::Builtin:
@@ -1900,6 +2119,79 @@ void Type::ClearLinkageCache() {
CanonicalType->TypeBits.CacheValidAndVisibility = 0;
}
+Qualifiers::ObjCLifetime Type::getObjCARCImplicitLifetime() const {
+ if (isObjCARCImplicitlyUnretainedType())
+ return Qualifiers::OCL_ExplicitNone;
+ return Qualifiers::OCL_Strong;
+}
+
+bool Type::isObjCARCImplicitlyUnretainedType() const {
+ assert(isObjCLifetimeType() &&
+ "cannot query implicit lifetime for non-inferrable type");
+
+ const Type *canon = getCanonicalTypeInternal().getTypePtr();
+
+ // Walk down to the base type. We don't care about qualifiers for this.
+ while (const ArrayType *array = dyn_cast<ArrayType>(canon))
+ canon = array->getElementType().getTypePtr();
+
+ if (const ObjCObjectPointerType *opt
+ = dyn_cast<ObjCObjectPointerType>(canon)) {
+ // Class and Class<Protocol> don't require retension.
+ if (opt->getObjectType()->isObjCClass())
+ return true;
+ }
+
+ return false;
+}
+
+bool Type::isObjCNSObjectType() const {
+ if (const TypedefType *typedefType = dyn_cast<TypedefType>(this))
+ return typedefType->getDecl()->hasAttr<ObjCNSObjectAttr>();
+ return false;
+}
+bool Type::isObjCRetainableType() const {
+ return isObjCObjectPointerType() ||
+ isBlockPointerType() ||
+ isObjCNSObjectType();
+}
+bool Type::isObjCIndirectLifetimeType() const {
+ if (isObjCLifetimeType())
+ return true;
+ if (const PointerType *OPT = getAs<PointerType>())
+ return OPT->getPointeeType()->isObjCIndirectLifetimeType();
+ if (const ReferenceType *Ref = getAs<ReferenceType>())
+ return Ref->getPointeeType()->isObjCIndirectLifetimeType();
+ if (const MemberPointerType *MemPtr = getAs<MemberPointerType>())
+ return MemPtr->getPointeeType()->isObjCIndirectLifetimeType();
+ return false;
+}
+
+/// Returns true if objects of this type have lifetime semantics under
+/// ARC.
+bool Type::isObjCLifetimeType() const {
+ const Type *type = this;
+ while (const ArrayType *array = type->getAsArrayTypeUnsafe())
+ type = array->getElementType().getTypePtr();
+ return type->isObjCRetainableType();
+}
+
+/// \brief Determine whether the given type T is a "bridgable" Objective-C type,
+/// which is either an Objective-C object pointer type or an
+bool Type::isObjCARCBridgableType() const {
+ return isObjCObjectPointerType() || isBlockPointerType();
+}
+
+/// \brief Determine whether the given type T is a "bridgeable" C type.
+bool Type::isCARCBridgableType() const {
+ const PointerType *Pointer = getAs<PointerType>();
+ if (!Pointer)
+ return false;
+
+ QualType Pointee = Pointer->getPointeeType();
+ return Pointee->isVoidType() || Pointee->isRecordType();
+}
+
bool Type::hasSizedVLAType() const {
if (!isVariablyModifiedType()) return false;
@@ -1919,6 +2211,18 @@ bool Type::hasSizedVLAType() const {
}
QualType::DestructionKind QualType::isDestructedTypeImpl(QualType type) {
+ switch (type.getObjCLifetime()) {
+ case Qualifiers::OCL_None:
+ case Qualifiers::OCL_ExplicitNone:
+ case Qualifiers::OCL_Autoreleasing:
+ break;
+
+ case Qualifiers::OCL_Strong:
+ return DK_objc_strong_lifetime;
+ case Qualifiers::OCL_Weak:
+ return DK_objc_weak_lifetime;
+ }
+
/// Currently, the only destruction kind we recognize is C++ objects
/// with non-trivial destructors.
const CXXRecordDecl *record =
@@ -1928,3 +2232,24 @@ QualType::DestructionKind QualType::isDestructedTypeImpl(QualType type) {
return DK_none;
}
+
+bool QualType::hasTrivialCopyAssignment(ASTContext &Context) const {
+ switch (getObjCLifetime()) {
+ case Qualifiers::OCL_None:
+ break;
+
+ case Qualifiers::OCL_ExplicitNone:
+ return true;
+
+ case Qualifiers::OCL_Autoreleasing:
+ case Qualifiers::OCL_Strong:
+ case Qualifiers::OCL_Weak:
+ return !Context.getLangOptions().ObjCAutoRefCount;
+ }
+
+ if (const CXXRecordDecl *Record
+ = getTypePtr()->getBaseElementTypeUnsafe()->getAsCXXRecordDecl())
+ return Record->hasTrivialCopyAssignment();
+
+ return true;
+}
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index 4519606f6e82..b89d2aa31676 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -24,6 +24,23 @@
using namespace clang;
namespace {
+ /// \brief RAII object that enables printing of the ARC __strong lifetime
+ /// qualifier.
+ class IncludeStrongLifetimeRAII {
+ PrintingPolicy &Policy;
+ bool Old;
+
+ public:
+ explicit IncludeStrongLifetimeRAII(PrintingPolicy &Policy)
+ : Policy(Policy), Old(Policy.SuppressStrongLifetime) {
+ Policy.SuppressStrongLifetime = false;
+ }
+
+ ~IncludeStrongLifetimeRAII() {
+ Policy.SuppressStrongLifetime = Old;
+ }
+ };
+
class TypePrinter {
PrintingPolicy Policy;
@@ -78,7 +95,7 @@ void TypePrinter::print(const Type *T, Qualifiers Quals, std::string &buffer) {
// "int * const", printing "const int *" is different. Only do this when the
// type expands to a simple string.
bool CanPrefixQualifiers = false;
-
+ bool NeedARCStrongQualifier = false;
Type::TypeClass TC = T->getTypeClass();
if (const AutoType *AT = dyn_cast<AutoType>(T))
TC = AT->desugar()->getTypeClass();
@@ -114,15 +131,18 @@ void TypePrinter::print(const Type *T, Qualifiers Quals, std::string &buffer) {
T->isObjCQualifiedIdType() || T->isObjCQualifiedClassType();
break;
+ case Type::ConstantArray:
+ case Type::IncompleteArray:
+ case Type::VariableArray:
+ case Type::DependentSizedArray:
+ NeedARCStrongQualifier = true;
+ // Fall through
+
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:
@@ -139,13 +159,20 @@ void TypePrinter::print(const Type *T, Qualifiers Quals, std::string &buffer) {
if (!CanPrefixQualifiers && !Quals.empty()) {
std::string qualsBuffer;
- Quals.getAsStringInternal(qualsBuffer, Policy);
+ if (NeedARCStrongQualifier) {
+ IncludeStrongLifetimeRAII Strong(Policy);
+ Quals.getAsStringInternal(qualsBuffer, Policy);
+ } else {
+ Quals.getAsStringInternal(qualsBuffer, Policy);
+ }
- if (!buffer.empty()) {
- qualsBuffer += ' ';
- qualsBuffer += buffer;
+ if (!qualsBuffer.empty()) {
+ if (!buffer.empty()) {
+ qualsBuffer += ' ';
+ qualsBuffer += buffer;
+ }
+ std::swap(buffer, qualsBuffer);
}
- std::swap(buffer, qualsBuffer);
}
switch (T->getTypeClass()) {
@@ -159,13 +186,20 @@ void TypePrinter::print(const Type *T, Qualifiers Quals, std::string &buffer) {
// If we're adding the qualifiers as a prefix, do it now.
if (CanPrefixQualifiers && !Quals.empty()) {
std::string qualsBuffer;
- Quals.getAsStringInternal(qualsBuffer, Policy);
-
- if (!buffer.empty()) {
- qualsBuffer += ' ';
- qualsBuffer += buffer;
+ if (NeedARCStrongQualifier) {
+ IncludeStrongLifetimeRAII Strong(Policy);
+ Quals.getAsStringInternal(qualsBuffer, Policy);
+ } else {
+ Quals.getAsStringInternal(qualsBuffer, Policy);
+ }
+
+ if (!qualsBuffer.empty()) {
+ if (!buffer.empty()) {
+ qualsBuffer += ' ';
+ qualsBuffer += buffer;
+ }
+ std::swap(buffer, qualsBuffer);
}
- std::swap(buffer, qualsBuffer);
}
}
@@ -192,6 +226,7 @@ void TypePrinter::printPointer(const PointerType *T, std::string &S) {
if (isa<ArrayType>(T->getPointeeType()))
S = '(' + S + ')';
+ IncludeStrongLifetimeRAII Strong(Policy);
print(T->getPointeeType(), S);
}
@@ -209,6 +244,7 @@ void TypePrinter::printLValueReference(const LValueReferenceType *T,
if (isa<ArrayType>(T->getPointeeTypeAsWritten()))
S = '(' + S + ')';
+ IncludeStrongLifetimeRAII Strong(Policy);
print(T->getPointeeTypeAsWritten(), S);
}
@@ -221,6 +257,7 @@ void TypePrinter::printRValueReference(const RValueReferenceType *T,
if (isa<ArrayType>(T->getPointeeTypeAsWritten()))
S = '(' + S + ')';
+ IncludeStrongLifetimeRAII Strong(Policy);
print(T->getPointeeTypeAsWritten(), S);
}
@@ -236,6 +273,7 @@ void TypePrinter::printMemberPointer(const MemberPointerType *T,
if (isa<ArrayType>(T->getPointeeType()))
S = '(' + S + ')';
+ IncludeStrongLifetimeRAII Strong(Policy);
print(T->getPointeeType(), S);
}
@@ -245,12 +283,14 @@ void TypePrinter::printConstantArray(const ConstantArrayType *T,
S += llvm::utostr(T->getSize().getZExtValue());
S += ']';
+ IncludeStrongLifetimeRAII Strong(Policy);
print(T->getElementType(), S);
}
void TypePrinter::printIncompleteArray(const IncompleteArrayType *T,
std::string &S) {
S += "[]";
+ IncludeStrongLifetimeRAII Strong(Policy);
print(T->getElementType(), S);
}
@@ -276,6 +316,7 @@ void TypePrinter::printVariableArray(const VariableArrayType *T,
}
S += ']';
+ IncludeStrongLifetimeRAII Strong(Policy);
print(T->getElementType(), S);
}
@@ -291,6 +332,7 @@ void TypePrinter::printDependentSizedArray(const DependentSizedArrayType *T,
}
S += ']';
+ IncludeStrongLifetimeRAII Strong(Policy);
print(T->getElementType(), S);
}
@@ -518,6 +560,7 @@ void TypePrinter::printUnaryTransform(const UnaryTransformType *T,
if (!S.empty())
S = ' ' + S;
std::string Str;
+ IncludeStrongLifetimeRAII Strong(Policy);
print(T->getBaseType(), Str);
switch (T->getUTTKind()) {
@@ -552,6 +595,7 @@ void TypePrinter::AppendScope(DeclContext *DC, std::string &Buffer) {
Buffer += "<anonymous>";
} else if (ClassTemplateSpecializationDecl *Spec
= dyn_cast<ClassTemplateSpecializationDecl>(DC)) {
+ IncludeStrongLifetimeRAII Strong(Policy);
const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
std::string TemplateArgsStr
= TemplateSpecializationType::PrintTemplateArgumentList(
@@ -642,6 +686,7 @@ void TypePrinter::printTag(TagDecl *D, std::string &InnerString) {
Args = TemplateArgs.data();
NumArgs = TemplateArgs.size();
}
+ IncludeStrongLifetimeRAII Strong(Policy);
Buffer += TemplateSpecializationType::PrintTemplateArgumentList(Args,
NumArgs,
Policy);
@@ -677,18 +722,21 @@ void TypePrinter::printTemplateTypeParm(const TemplateTypeParmType *T,
void TypePrinter::printSubstTemplateTypeParm(const SubstTemplateTypeParmType *T,
std::string &S) {
+ IncludeStrongLifetimeRAII Strong(Policy);
print(T->getReplacementType(), S);
}
void TypePrinter::printSubstTemplateTypeParmPack(
const SubstTemplateTypeParmPackType *T,
std::string &S) {
+ IncludeStrongLifetimeRAII Strong(Policy);
printTemplateTypeParm(T->getReplacedParameter(), S);
}
void TypePrinter::printTemplateSpecialization(
const TemplateSpecializationType *T,
std::string &S) {
+ IncludeStrongLifetimeRAII Strong(Policy);
std::string SpecString;
{
@@ -765,6 +813,7 @@ void TypePrinter::printDependentName(const DependentNameType *T, std::string &S)
void TypePrinter::printDependentTemplateSpecialization(
const DependentTemplateSpecializationType *T, std::string &S) {
+ IncludeStrongLifetimeRAII Strong(Policy);
std::string MyString;
{
llvm::raw_string_ostream OS(MyString);
@@ -796,8 +845,9 @@ void TypePrinter::printPackExpansion(const PackExpansionType *T,
void TypePrinter::printAttributed(const AttributedType *T,
std::string &S) {
- // Prefer the macro forms of the GC qualifiers.
- if (T->getAttrKind() == AttributedType::attr_objc_gc)
+ // Prefer the macro forms of the GC and ownership qualifiers.
+ if (T->getAttrKind() == AttributedType::attr_objc_gc ||
+ T->getAttrKind() == AttributedType::attr_objc_ownership)
return print(T->getEquivalentType(), S);
print(T->getModifiedType(), S);
@@ -866,6 +916,18 @@ void TypePrinter::printAttributed(const AttributedType *T,
break;
}
+ case AttributedType::attr_objc_ownership:
+ S += "objc_ownership(";
+ switch (T->getEquivalentType().getObjCLifetime()) {
+ case Qualifiers::OCL_None: llvm_unreachable("no ownership!"); break;
+ case Qualifiers::OCL_ExplicitNone: S += "none"; break;
+ case Qualifiers::OCL_Strong: S += "strong"; break;
+ case Qualifiers::OCL_Weak: S += "weak"; break;
+ case Qualifiers::OCL_Autoreleasing: S += "autoreleasing"; break;
+ }
+ S += ")";
+ break;
+
case AttributedType::attr_noreturn: S += "noreturn"; break;
case AttributedType::attr_cdecl: S += "cdecl"; break;
case AttributedType::attr_fastcall: S += "fastcall"; break;
@@ -1080,7 +1142,7 @@ std::string Qualifiers::getAsString() const {
// prefix a space if the string is non-empty. Will not append a final
// space.
void Qualifiers::getAsStringInternal(std::string &S,
- const PrintingPolicy&) const {
+ const PrintingPolicy& Policy) const {
AppendTypeQualList(S, getCVRQualifiers());
if (unsigned addrspace = getAddressSpace()) {
if (!S.empty()) S += ' ';
@@ -1095,6 +1157,23 @@ void Qualifiers::getAsStringInternal(std::string &S,
else
S += "__strong";
}
+ if (Qualifiers::ObjCLifetime lifetime = getObjCLifetime()) {
+ if (!S.empty() &&
+ !(lifetime == Qualifiers::OCL_Strong && Policy.SuppressStrongLifetime))
+ S += ' ';
+
+ switch (lifetime) {
+ case Qualifiers::OCL_None: llvm_unreachable("none but true");
+ case Qualifiers::OCL_ExplicitNone: S += "__unsafe_unretained"; break;
+ case Qualifiers::OCL_Strong:
+ if (!Policy.SuppressStrongLifetime)
+ S += "__strong";
+ break;
+
+ case Qualifiers::OCL_Weak: S += "__weak"; break;
+ case Qualifiers::OCL_Autoreleasing: S += "__autoreleasing"; break;
+ }
+ }
}
std::string QualType::getAsString(const Type *ty, Qualifiers qs) {
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index 3e540203eaa0..f231c147f11e 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -776,7 +776,7 @@ LocalScope* CFGBuilder::addLocalScopeForVarDecl(VarDecl* VD,
QT = RT->getPointeeType();
if (!QT.isConstQualified())
return Scope;
- if (!VD->getInit() || !VD->getInit()->Classify(*Context).isRValue())
+ if (!VD->extendsLifetimeOfTemporary())
return Scope;
}
@@ -2763,6 +2763,10 @@ tryAgain:
case Stmt::ParenExprClass:
E = cast<ParenExpr>(E)->getSubExpr();
goto tryAgain;
+
+ case Stmt::MaterializeTemporaryExprClass:
+ E = cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr();
+ goto tryAgain;
}
}
diff --git a/lib/Analysis/CocoaConventions.cpp b/lib/Analysis/CocoaConventions.cpp
index 946c38c875d5..90f7092f90ee 100644
--- a/lib/Analysis/CocoaConventions.cpp
+++ b/lib/Analysis/CocoaConventions.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This file defines
+// This file implements cocoa naming convention analysis.
//
//===----------------------------------------------------------------------===//
@@ -36,8 +36,10 @@ using llvm::StringRef;
// not release it."
//
-cocoa::NamingConvention cocoa::deriveNamingConvention(Selector S) {
- switch (S.getMethodFamily()) {
+cocoa::NamingConvention cocoa::deriveNamingConvention(Selector S,
+ const ObjCMethodDecl *MD) {
+ switch (MD && MD->hasAttr<ObjCMethodFamilyAttr>()? MD->getMethodFamily()
+ : S.getMethodFamily()) {
case OMF_None:
case OMF_autorelease:
case OMF_dealloc:
@@ -45,6 +47,7 @@ cocoa::NamingConvention cocoa::deriveNamingConvention(Selector S) {
case OMF_retain:
case OMF_retainCount:
case OMF_self:
+ case OMF_performSelector:
return NoConvention;
case OMF_init:
@@ -83,12 +86,12 @@ bool cocoa::isRefType(QualType RetTy, llvm::StringRef Prefix,
return Name.startswith(Prefix);
}
-bool cocoa::isCFObjectRef(QualType T) {
- return isRefType(T, "CF") || // Core Foundation.
- isRefType(T, "CG") || // Core Graphics.
- isRefType(T, "DADisk") || // Disk Arbitration API.
- isRefType(T, "DADissenter") ||
- isRefType(T, "DASessionRef");
+bool coreFoundation::isCFObjectRef(QualType T) {
+ return cocoa::isRefType(T, "CF") || // Core Foundation.
+ cocoa::isRefType(T, "CG") || // Core Graphics.
+ cocoa::isRefType(T, "DADisk") || // Disk Arbitration API.
+ cocoa::isRefType(T, "DADissenter") ||
+ cocoa::isRefType(T, "DASessionRef");
}
@@ -123,3 +126,47 @@ bool cocoa::isCocoaObjectRef(QualType Ty) {
return false;
}
+
+bool coreFoundation::followsCreateRule(llvm::StringRef functionName) {
+ llvm::StringRef::iterator it = functionName.begin();
+ llvm::StringRef::iterator start = it;
+ llvm::StringRef::iterator endI = functionName.end();
+
+ while (true) {
+ // Scan for the start of 'create' or 'copy'.
+ for ( ; it != endI ; ++it) {
+ // Search for the first character. It can either be 'C' or 'c'.
+ char ch = *it;
+ if (ch == 'C' || ch == 'c') {
+ ++it;
+ break;
+ }
+ }
+
+ // Did we hit the end of the string? If so, we didn't find a match.
+ if (it == endI)
+ return false;
+
+ // Scan for *lowercase* 'reate' or 'opy', followed by no lowercase
+ // character.
+ llvm::StringRef suffix = functionName.substr(it - start);
+ if (suffix.startswith("reate")) {
+ it += 5;
+ }
+ else if (suffix.startswith("opy")) {
+ it += 3;
+ }
+ else {
+ // Keep scanning.
+ continue;
+ }
+
+ if (it == endI || !islower(*it))
+ return true;
+
+ // If we matched a lowercase character, it isn't the end of the
+ // word. Keep scanning.
+ }
+
+ return false;
+}
diff --git a/lib/Analysis/FormatString.cpp b/lib/Analysis/FormatString.cpp
index c1b5ea8a652a..5f3cd4c61549 100644
--- a/lib/Analysis/FormatString.cpp
+++ b/lib/Analysis/FormatString.cpp
@@ -219,6 +219,7 @@ bool ArgTypeResult::matchesType(ASTContext &C, QualType argTy) const {
argTy = C.getCanonicalType(argTy).getUnqualifiedType();
if (T == argTy)
return true;
+ // Check for "compatible types".
if (const BuiltinType *BT = argTy->getAs<BuiltinType>())
switch (BT->getKind()) {
default:
@@ -227,7 +228,7 @@ bool ArgTypeResult::matchesType(ASTContext &C, QualType argTy) const {
case BuiltinType::SChar:
return T == C.UnsignedCharTy;
case BuiltinType::Char_U:
- case BuiltinType::UChar:
+ case BuiltinType::UChar:
return T == C.SignedCharTy;
case BuiltinType::Short:
return T == C.UnsignedShortTy;
diff --git a/lib/Analysis/ReachableCode.cpp b/lib/Analysis/ReachableCode.cpp
index 9ac456f53a67..c5b17fc77bb2 100644
--- a/lib/Analysis/ReachableCode.cpp
+++ b/lib/Analysis/ReachableCode.cpp
@@ -16,6 +16,7 @@
#include "llvm/ADT/SmallVector.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
#include "clang/AST/StmtCXX.h"
#include "clang/Analysis/Analyses/ReachableCode.h"
#include "clang/Analysis/CFG.h"
@@ -108,6 +109,11 @@ static SourceLocation GetUnreachableLoc(const CFGBlock &b, SourceRange &R1,
case Stmt::CXXTryStmtClass: {
return cast<CXXTryStmt>(S)->getHandler(0)->getCatchLoc();
}
+ case Expr::ObjCBridgedCastExprClass: {
+ const ObjCBridgedCastExpr *CSC = cast<ObjCBridgedCastExpr>(S);
+ R1 = CSC->getSubExpr()->getSourceRange();
+ return CSC->getLParenLoc();
+ }
default: ;
}
R1 = S->getSourceRange();
diff --git a/lib/Analysis/UninitializedValues.cpp b/lib/Analysis/UninitializedValues.cpp
index e80e282813af..1d6959d81b16 100644
--- a/lib/Analysis/UninitializedValues.cpp
+++ b/lib/Analysis/UninitializedValues.cpp
@@ -288,28 +288,28 @@ class DataflowWorklist {
public:
DataflowWorklist(const CFG &cfg) : enqueuedBlocks(cfg.getNumBlockIDs()) {}
- void enqueue(const CFGBlock *block);
void enqueueSuccessors(const CFGBlock *block);
const CFGBlock *dequeue();
-
};
}
-void DataflowWorklist::enqueue(const CFGBlock *block) {
- if (!block)
- return;
- unsigned idx = block->getBlockID();
- if (enqueuedBlocks[idx])
- return;
- worklist.push_back(block);
- enqueuedBlocks[idx] = true;
-}
-
void DataflowWorklist::enqueueSuccessors(const clang::CFGBlock *block) {
+ unsigned OldWorklistSize = worklist.size();
for (CFGBlock::const_succ_iterator I = block->succ_begin(),
E = block->succ_end(); I != E; ++I) {
- enqueue(*I);
+ const CFGBlock *Successor = *I;
+ if (!Successor || enqueuedBlocks[Successor->getBlockID()])
+ continue;
+ worklist.push_back(Successor);
+ enqueuedBlocks[Successor->getBlockID()] = true;
}
+ if (OldWorklistSize == 0 || OldWorklistSize == worklist.size())
+ return;
+
+ // Rotate the newly added blocks to the start of the worklist so that it forms
+ // a proper queue when we pop off the end of the worklist.
+ std::rotate(worklist.begin(), worklist.begin() + OldWorklistSize,
+ worklist.end());
}
const CFGBlock *DataflowWorklist::dequeue() {
@@ -654,15 +654,19 @@ static bool runOnBlock(const CFGBlock *block, const CFG &cfg,
return vals.updateValueVectorWithScratch(block);
}
-void clang::runUninitializedVariablesAnalysis(const DeclContext &dc,
- const CFG &cfg,
- AnalysisContext &ac,
- UninitVariablesHandler &handler) {
+void clang::runUninitializedVariablesAnalysis(
+ const DeclContext &dc,
+ const CFG &cfg,
+ AnalysisContext &ac,
+ UninitVariablesHandler &handler,
+ UninitVariablesAnalysisStats &stats) {
CFGBlockValues vals(cfg);
vals.computeSetOfDeclarations(dc);
if (vals.hasNoDeclarations())
return;
+ stats.NumVariablesAnalyzed = vals.getNumEntries();
+
// Mark all variables uninitialized at the entry.
const CFGBlock &entry = cfg.getEntry();
for (CFGBlock::const_succ_iterator i = entry.succ_begin(),
@@ -684,7 +688,8 @@ void clang::runUninitializedVariablesAnalysis(const DeclContext &dc,
while (const CFGBlock *block = worklist.dequeue()) {
// Did the block change?
- bool changed = runOnBlock(block, cfg, ac, vals, wasAnalyzed);
+ bool changed = runOnBlock(block, cfg, ac, vals, wasAnalyzed);
+ ++stats.NumBlockVisits;
if (changed || !previouslyVisited[block->getBlockID()])
worklist.enqueueSuccessors(block);
previouslyVisited[block->getBlockID()] = true;
@@ -692,11 +697,12 @@ void clang::runUninitializedVariablesAnalysis(const DeclContext &dc,
// Run through the blocks one more time, and report uninitialized variabes.
for (CFG::const_iterator BI = cfg.begin(), BE = cfg.end(); BI != BE; ++BI) {
- if (wasAnalyzed[(*BI)->getBlockID()])
+ if (wasAnalyzed[(*BI)->getBlockID()]) {
runOnBlock(*BI, cfg, ac, vals, wasAnalyzed, &handler,
/* flagBlockUses */ true);
+ ++stats.NumBlockVisits;
+ }
}
}
UninitVariablesHandler::~UninitVariablesHandler() {}
-
diff --git a/lib/Basic/Builtins.cpp b/lib/Basic/Builtins.cpp
index 845ae81517da..7df24a03b03a 100644
--- a/lib/Basic/Builtins.cpp
+++ b/lib/Basic/Builtins.cpp
@@ -18,10 +18,10 @@
using namespace clang;
static const Builtin::Info BuiltinInfo[] = {
- { "not a builtin function", 0, 0, 0, ALL_LANGUAGES, false },
-#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES, false },
+ { "not a builtin function", 0, 0, 0, ALL_LANGUAGES },
+#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES },
#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER, BUILTIN_LANG) { #ID, TYPE, ATTRS, HEADER,\
- BUILTIN_LANG, false },
+ BUILTIN_LANG },
#include "clang/Basic/Builtins.def"
};
@@ -46,8 +46,7 @@ void Builtin::Context::InitializeBuiltins(IdentifierTable &Table,
const LangOptions& LangOpts) {
// Step #1: mark all target-independent builtins with their ID's.
for (unsigned i = Builtin::NotBuiltin+1; i != Builtin::FirstTSBuiltin; ++i)
- if (!BuiltinInfo[i].Suppressed &&
- (!LangOpts.NoBuiltin || !strchr(BuiltinInfo[i].Attributes, 'f'))) {
+ if (!LangOpts.NoBuiltin || !strchr(BuiltinInfo[i].Attributes, 'f')) {
if (LangOpts.ObjC1 ||
BuiltinInfo[i].builtin_lang != clang::OBJC_LANG)
Table.get(BuiltinInfo[i].Name).setBuiltinID(i);
@@ -55,10 +54,7 @@ void Builtin::Context::InitializeBuiltins(IdentifierTable &Table,
// Step #2: Register target-specific builtins.
for (unsigned i = 0, e = NumTSRecords; i != e; ++i)
- if (!TSRecords[i].Suppressed &&
- (!LangOpts.NoBuiltin ||
- (TSRecords[i].Attributes &&
- !strchr(TSRecords[i].Attributes, 'f'))))
+ if (!LangOpts.NoBuiltin || !strchr(TSRecords[i].Attributes, 'f'))
Table.get(TSRecords[i].Name).setBuiltinID(i+Builtin::FirstTSBuiltin);
}
@@ -67,16 +63,12 @@ Builtin::Context::GetBuiltinNames(llvm::SmallVectorImpl<const char *> &Names,
bool NoBuiltins) {
// Final all target-independent names
for (unsigned i = Builtin::NotBuiltin+1; i != Builtin::FirstTSBuiltin; ++i)
- if (!BuiltinInfo[i].Suppressed &&
- (!NoBuiltins || !strchr(BuiltinInfo[i].Attributes, 'f')))
+ if (!NoBuiltins || !strchr(BuiltinInfo[i].Attributes, 'f'))
Names.push_back(BuiltinInfo[i].Name);
// Find target-specific names.
for (unsigned i = 0, e = NumTSRecords; i != e; ++i)
- if (!TSRecords[i].Suppressed &&
- (!NoBuiltins ||
- (TSRecords[i].Attributes &&
- !strchr(TSRecords[i].Attributes, 'f'))))
+ if (!NoBuiltins || !strchr(TSRecords[i].Attributes, 'f'))
Names.push_back(TSRecords[i].Name);
}
diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp
index 11887ab0fe95..ae363a0df0d0 100644
--- a/lib/Basic/Diagnostic.cpp
+++ b/lib/Basic/Diagnostic.cpp
@@ -26,7 +26,8 @@ static void DummyArgToStringFn(Diagnostic::ArgumentKind AK, intptr_t QT,
const Diagnostic::ArgumentValue *PrevArgs,
unsigned NumPrevArgs,
llvm::SmallVectorImpl<char> &Output,
- void *Cookie) {
+ void *Cookie,
+ llvm::SmallVectorImpl<intptr_t> &QualTypeVals) {
const char *Str = "<can't format argument>";
Output.append(Str, Str+strlen(Str));
}
@@ -86,10 +87,12 @@ bool Diagnostic::popMappings(SourceLocation Loc) {
void Diagnostic::Reset() {
ErrorOccurred = false;
FatalErrorOccurred = false;
+ UnrecoverableErrorOccurred = false;
NumWarnings = 0;
NumErrors = 0;
NumErrorsSuppressed = 0;
+
CurDiagID = ~0U;
// Set LastDiagLevel to an "unset" state. If we set it to 'Ignored', notes
// using a Diagnostic associated to a translation unit that follow
@@ -542,7 +545,14 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
/// ConvertArgToString, allowing the implementation to avoid redundancies in
/// obvious cases.
llvm::SmallVector<Diagnostic::ArgumentValue, 8> FormattedArgs;
-
+
+ /// QualTypeVals - Pass a vector of arrays so that QualType names can be
+ /// compared to see if more information is needed to be printed.
+ llvm::SmallVector<intptr_t, 2> QualTypeVals;
+ for (unsigned i = 0, e = getNumArgs(); i < e; ++i)
+ if (getArgKind(i) == Diagnostic::ak_qualtype)
+ QualTypeVals.push_back(getRawArg(i));
+
while (DiagStr != DiagEnd) {
if (DiagStr[0] != '%') {
// Append non-%0 substrings to Str if we have one.
@@ -673,7 +683,7 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
Modifier, ModifierLen,
Argument, ArgumentLen,
FormattedArgs.data(), FormattedArgs.size(),
- OutStr);
+ OutStr, QualTypeVals);
break;
}
diff --git a/lib/Basic/DiagnosticIDs.cpp b/lib/Basic/DiagnosticIDs.cpp
index 6d7e3204cba3..147ba7e99e74 100644
--- a/lib/Basic/DiagnosticIDs.cpp
+++ b/lib/Basic/DiagnosticIDs.cpp
@@ -14,6 +14,7 @@
#include "clang/AST/ASTDiagnostic.h"
#include "clang/Analysis/AnalysisDiagnostic.h"
#include "clang/Basic/DiagnosticIDs.h"
+#include "clang/Basic/DiagnosticCategories.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Frontend/FrontendDiagnostic.h"
@@ -135,7 +136,7 @@ static const unsigned StaticDiagInfoSize =
sizeof(StaticDiagInfo)/sizeof(StaticDiagInfo[0])-1;
/// To be sorted before first use (since it's splitted among multiple files)
-static StaticDiagNameIndexRec StaticDiagNameIndex[] = {
+static const StaticDiagNameIndexRec StaticDiagNameIndex[] = {
#define DIAG_NAME_INDEX(ENUM) { #ENUM, diag::ENUM, STR_SIZE(#ENUM, uint8_t) },
#include "clang/Basic/DiagnosticIndexName.inc"
#undef DIAG_NAME_INDEX
@@ -199,19 +200,21 @@ unsigned DiagnosticIDs::getCategoryNumberForDiag(unsigned DiagID) {
return 0;
}
-// The diagnostic category names.
-struct StaticDiagCategoryRec {
- const char *NameStr;
- uint8_t NameLen;
+namespace {
+ // The diagnostic category names.
+ struct StaticDiagCategoryRec {
+ const char *NameStr;
+ uint8_t NameLen;
- llvm::StringRef getName() const {
- return llvm::StringRef(NameStr, NameLen);
- }
-};
+ llvm::StringRef getName() const {
+ return llvm::StringRef(NameStr, NameLen);
+ }
+ };
+}
-static StaticDiagCategoryRec CategoryNameTable[] = {
+static const StaticDiagCategoryRec CategoryNameTable[] = {
#define GET_CATEGORY_TABLE
-#define CATEGORY(X) { X, STR_SIZE(X, uint8_t) },
+#define CATEGORY(X, ENUM) { X, STR_SIZE(X, uint8_t) },
#include "clang/Basic/DiagnosticGroups.inc"
#undef GET_CATEGORY_TABLE
{ 0, 0 }
@@ -261,7 +264,7 @@ llvm::StringRef DiagnosticIDs::getName(unsigned DiagID) {
/// getIdFromName - Given a diagnostic name, return its ID, or 0
unsigned DiagnosticIDs::getIdFromName(llvm::StringRef Name) {
- StaticDiagNameIndexRec *StaticDiagNameIndexEnd =
+ const StaticDiagNameIndexRec *StaticDiagNameIndexEnd =
StaticDiagNameIndex + StaticDiagNameIndexSize;
if (Name.empty()) { return diag::DIAG_UPPER_LIMIT; }
@@ -543,17 +546,21 @@ DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass,
return Result;
}
-struct WarningOption {
- // Be safe with the size of 'NameLen' because we don't statically check if the
- // size will fit in the field; the struct size won't decrease with a shorter
- // type anyway.
- size_t NameLen;
- const char *NameStr;
- const short *Members;
- const short *SubGroups;
-
- llvm::StringRef getName() const { return llvm::StringRef(NameStr, NameLen); }
-};
+namespace {
+ struct WarningOption {
+ // Be safe with the size of 'NameLen' because we don't statically check if
+ // the size will fit in the field; the struct size won't decrease with a
+ // shorter type anyway.
+ size_t NameLen;
+ const char *NameStr;
+ const short *Members;
+ const short *SubGroups;
+
+ llvm::StringRef getName() const {
+ return llvm::StringRef(NameStr, NameLen);
+ }
+ };
+}
#define GET_DIAG_ARRAYS
#include "clang/Basic/DiagnosticGroups.inc"
@@ -678,6 +685,12 @@ bool DiagnosticIDs::ProcessDiag(Diagnostic &Diag) const {
return false;
if (DiagLevel >= DiagnosticIDs::Error) {
+ Diag.TrapErrorOccurred = true;
+ if (isUnrecoverable(DiagID)) {
+ Diag.TrapUnrecoverableErrorOccurred = true;
+ Diag.UnrecoverableErrorOccurred = true;
+ }
+
if (Diag.Client->IncludeInDiagnosticCounts()) {
Diag.ErrorOccurred = true;
++Diag.NumErrors;
@@ -714,3 +727,25 @@ bool DiagnosticIDs::ProcessDiag(Diagnostic &Diag) const {
return true;
}
+
+bool DiagnosticIDs::isUnrecoverable(unsigned DiagID) const {
+ if (DiagID >= diag::DIAG_UPPER_LIMIT) {
+ // Custom diagnostics.
+ return CustomDiagInfo->getLevel(DiagID) >= DiagnosticIDs::Error;
+ }
+
+ // Only errors may be unrecoverable.
+ if (getBuiltinDiagClass(DiagID) < CLASS_ERROR)
+ return false;
+
+ if (DiagID == diag::err_unavailable ||
+ DiagID == diag::err_unavailable_message)
+ return false;
+
+ // Currently we consider all ARC errors as recoverable.
+ if (getCategoryNumberForDiag(DiagID) ==
+ diag::DiagCat_Automatic_Reference_Counting_Issue)
+ return false;
+
+ return true;
+}
diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp
index 4711faa1a519..188e2d46f587 100644
--- a/lib/Basic/IdentifierTable.cpp
+++ b/lib/Basic/IdentifierTable.cpp
@@ -17,6 +17,7 @@
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/raw_ostream.h"
#include <cstdio>
@@ -92,7 +93,8 @@ namespace {
KEYBORLAND = 0x100,
KEYOPENCL = 0x200,
KEYC1X = 0x400,
- KEYALL = 0x7ff
+ KEYARC = 0x800,
+ KEYALL = 0x0fff
};
}
@@ -120,7 +122,8 @@ static void AddKeyword(llvm::StringRef Keyword,
else if (LangOpts.OpenCL && (Flags & KEYOPENCL)) AddResult = 2;
else if (!LangOpts.CPlusPlus && (Flags & KEYNOCXX)) AddResult = 2;
else if (LangOpts.C1X && (Flags & KEYC1X)) AddResult = 2;
-
+ else if (LangOpts.ObjCAutoRefCount && (Flags & KEYARC)) AddResult = 2;
+
// Don't add this keyword if disabled in this language.
if (AddResult == 0) return;
@@ -394,6 +397,8 @@ ObjCMethodFamily Selector::getMethodFamilyImpl(Selector sel) {
if (name == "retainCount") return OMF_retainCount;
if (name == "self") return OMF_self;
}
+
+ if (name == "performSelector") return OMF_performSelector;
// The other method families may begin with a prefix of underscores.
while (!name.empty() && name.front() == '_')
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index 2de8ab7528ab..45922c15527f 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -169,11 +169,11 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag,
return Buffer.getPointer();
}
-unsigned LineTableInfo::getLineTableFilenameID(const char *Ptr, unsigned Len) {
+unsigned LineTableInfo::getLineTableFilenameID(llvm::StringRef Name) {
// Look up the filename in the string table, returning the pre-existing value
// if it exists.
llvm::StringMapEntry<unsigned> &Entry =
- FilenameIDs.GetOrCreateValue(Ptr, Ptr+Len, ~0U);
+ FilenameIDs.GetOrCreateValue(Name, ~0U);
if (Entry.getValue() != ~0U)
return Entry.getValue();
@@ -277,10 +277,10 @@ void LineTableInfo::AddEntry(unsigned FID,
/// getLineTableFilenameID - Return the uniqued ID for the specified filename.
///
-unsigned SourceManager::getLineTableFilenameID(const char *Ptr, unsigned Len) {
+unsigned SourceManager::getLineTableFilenameID(llvm::StringRef Name) {
if (LineTable == 0)
LineTable = new LineTableInfo();
- return LineTable->getLineTableFilenameID(Ptr, Len);
+ return LineTable->getLineTableFilenameID(Name);
}
@@ -531,16 +531,31 @@ FileID SourceManager::createFileID(const ContentCache *File,
return LastFileIDLookup = FID;
}
-/// createInstantiationLoc - Return a new SourceLocation that encodes the fact
-/// that a token from SpellingLoc should actually be referenced from
-/// InstantiationLoc.
+SourceLocation
+SourceManager::createMacroArgInstantiationLoc(SourceLocation SpellingLoc,
+ SourceLocation ILoc,
+ unsigned TokLength) {
+ InstantiationInfo II =
+ InstantiationInfo::createForMacroArg(SpellingLoc, ILoc);
+ return createInstantiationLocImpl(II, TokLength);
+}
+
SourceLocation SourceManager::createInstantiationLoc(SourceLocation SpellingLoc,
SourceLocation ILocStart,
SourceLocation ILocEnd,
unsigned TokLength,
unsigned PreallocatedID,
unsigned Offset) {
- InstantiationInfo II = InstantiationInfo::get(ILocStart,ILocEnd, SpellingLoc);
+ InstantiationInfo II =
+ InstantiationInfo::create(SpellingLoc, ILocStart, ILocEnd);
+ return createInstantiationLocImpl(II, TokLength, PreallocatedID, Offset);
+}
+
+SourceLocation
+SourceManager::createInstantiationLocImpl(const InstantiationInfo &II,
+ unsigned TokLength,
+ unsigned PreallocatedID,
+ unsigned Offset) {
if (PreallocatedID) {
// If we're filling in a preallocated ID, just load in the
// instantiation entry and return.
@@ -749,18 +764,19 @@ SourceLocation SourceManager::getSpellingLocSlowCase(SourceLocation Loc) const {
std::pair<FileID, unsigned>
-SourceManager::getDecomposedInstantiationLocSlowCase(const SrcMgr::SLocEntry *E,
- unsigned Offset) const {
+SourceManager::getDecomposedInstantiationLocSlowCase(
+ const SrcMgr::SLocEntry *E) const {
// If this is an instantiation record, walk through all the instantiation
// points.
FileID FID;
SourceLocation Loc;
+ unsigned Offset;
do {
Loc = E->getInstantiation().getInstantiationLocStart();
FID = getFileID(Loc);
E = &getSLocEntry(FID);
- Offset += Loc.getOffset()-E->getOffset();
+ Offset = Loc.getOffset()-E->getOffset();
} while (!Loc.isFileID());
return std::make_pair(FID, Offset);
@@ -823,6 +839,14 @@ SourceManager::getInstantiationRange(SourceLocation Loc) const {
return Res;
}
+bool SourceManager::isMacroArgInstantiation(SourceLocation Loc) const {
+ if (!Loc.isMacroID()) return false;
+
+ FileID FID = getFileID(Loc);
+ const SrcMgr::SLocEntry *E = &getSLocEntry(FID);
+ const SrcMgr::InstantiationInfo &II = E->getInstantiation();
+ return II.isMacroArgInstantiation();
+}
//===----------------------------------------------------------------------===//
@@ -917,7 +941,7 @@ static void ComputeLineNumbers(Diagnostic &Diag, ContentCache *FI,
// Find the file offsets of all of the *physical* source lines. This does
// not look at trigraphs, escaped newlines, or anything else tricky.
- std::vector<unsigned> LineOffsets;
+ llvm::SmallVector<unsigned, 256> LineOffsets;
// Line #1 starts at char 0.
LineOffsets.push_back(0);
@@ -1213,73 +1237,6 @@ PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc) const {
return PresumedLoc(Filename, LineNo, ColNo, IncludeLoc);
}
-/// \brief Returns true if the given MacroID location points at the first
-/// token of the macro instantiation.
-bool SourceManager::isAtStartOfMacroInstantiation(SourceLocation loc) const {
- assert(loc.isValid() && loc.isMacroID() && "Expected a valid macro loc");
-
- unsigned FID = getFileID(loc).ID;
- assert(FID > 1);
- std::pair<SourceLocation, SourceLocation>
- instRange = getImmediateInstantiationRange(loc);
-
- bool invalid = false;
- const SrcMgr::SLocEntry &Entry = getSLocEntry(FID-1, &invalid);
- if (invalid)
- return false;
-
- // If the FileID immediately before it is a file then this is the first token
- // in the macro.
- if (Entry.isFile())
- return true;
-
- // If the FileID immediately before it (which is a macro token) is the
- // immediate instantiated macro, check this macro token's location.
- if (getFileID(instRange.second).ID == FID-1)
- return isAtStartOfMacroInstantiation(instRange.first);
-
- // If the FileID immediately before it (which is a macro token) came from a
- // different instantiation, then this is the first token in the macro.
- if (getInstantiationLoc(Entry.getInstantiation().getInstantiationLocStart())
- != getInstantiationLoc(loc))
- return true;
-
- // It is inside the macro or the last token in the macro.
- return false;
-}
-
-/// \brief Returns true if the given MacroID location points at the last
-/// token of the macro instantiation.
-bool SourceManager::isAtEndOfMacroInstantiation(SourceLocation loc) const {
- assert(loc.isValid() && loc.isMacroID() && "Expected a valid macro loc");
-
- unsigned FID = getFileID(loc).ID;
- assert(FID > 1);
- std::pair<SourceLocation, SourceLocation>
- instRange = getInstantiationRange(loc);
-
- // If there's no FileID after it, it is the last token in the macro.
- if (FID+1 == sloc_entry_size())
- return true;
-
- bool invalid = false;
- const SrcMgr::SLocEntry &Entry = getSLocEntry(FID+1, &invalid);
- if (invalid)
- return false;
-
- // If the FileID immediately after it is a file or a macro token which
- // came from a different instantiation, then this is the last token in the
- // macro.
- if (Entry.isFile())
- return true;
- if (getInstantiationLoc(Entry.getInstantiation().getInstantiationLocStart())
- != instRange.first)
- return true;
-
- // It is inside the macro or the first token in the macro.
- return false;
-}
-
//===----------------------------------------------------------------------===//
// Other miscellaneous methods.
//===----------------------------------------------------------------------===//
@@ -1474,8 +1431,6 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS,
// reflect the order that the tokens, pointed to by these locations, were
// instantiated (during parsing each token that is instantiated by a macro,
// expands the SLocEntries).
- if (LHS.isMacroID() && RHS.isMacroID())
- return LHS.getOffset() < RHS.getOffset();
std::pair<FileID, unsigned> LOffs = getDecomposedLoc(LHS);
std::pair<FileID, unsigned> ROffs = getDecomposedLoc(RHS);
@@ -1562,7 +1517,9 @@ void SourceManager::PrintStats() const {
llvm::errs() << "\n*** Source Manager Stats:\n";
llvm::errs() << FileInfos.size() << " files mapped, " << MemBufferInfos.size()
<< " mem buffers mapped.\n";
- llvm::errs() << SLocEntryTable.size() << " SLocEntry's allocated, "
+ llvm::errs() << SLocEntryTable.size() << " SLocEntry's allocated ("
+ << SLocEntryTable.capacity()*sizeof(SrcMgr::SLocEntry)
+ << " bytes of capacity), "
<< NextOffset << "B of Sloc address space used.\n";
unsigned NumLineNumsComputed = 0;
diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp
index dcf0cb4237a9..30a9bdb31774 100644
--- a/lib/Basic/TargetInfo.cpp
+++ b/lib/Basic/TargetInfo.cpp
@@ -181,6 +181,14 @@ static llvm::StringRef removeGCCRegisterPrefix(llvm::StringRef Name) {
return Name;
}
+/// isValidClobber - Returns whether the passed in string is
+/// a valid clobber in an inline asm statement. This is used by
+/// Sema.
+bool TargetInfo::isValidClobber(llvm::StringRef Name) const {
+ return (isValidGCCRegisterName(Name) ||
+ Name == "memory" || Name == "cc");
+}
+
/// isValidGCCRegisterName - Returns whether the passed in string
/// is a valid register name according to GCC. This is used by Sema for
/// inline asm statements.
@@ -194,9 +202,6 @@ bool TargetInfo::isValidGCCRegisterName(llvm::StringRef Name) const {
// Get rid of any register prefix.
Name = removeGCCRegisterPrefix(Name);
- if (Name == "memory" || Name == "cc")
- return true;
-
getGCCRegNames(Names, NumNames);
// If we have a number it maps to an entry in the register name array.
@@ -212,6 +217,20 @@ bool TargetInfo::isValidGCCRegisterName(llvm::StringRef Name) const {
return true;
}
+ // Check any additional names that we have.
+ const AddlRegName *AddlNames;
+ unsigned NumAddlNames;
+ getGCCAddlRegNames(AddlNames, NumAddlNames);
+ for (unsigned i = 0; i < NumAddlNames; i++)
+ for (unsigned j = 0; j < llvm::array_lengthof(AddlNames[i].Names); j++) {
+ if (!AddlNames[i].Names[j])
+ break;
+ // Make sure the register that the additional name is for is within
+ // the bounds of the register names from above.
+ if (AddlNames[i].Names[j] == Name && AddlNames[i].RegNum < NumNames)
+ return true;
+ }
+
// Now check aliases.
const GCCRegAlias *Aliases;
unsigned NumAliases;
@@ -251,6 +270,20 @@ TargetInfo::getNormalizedGCCRegisterName(llvm::StringRef Name) const {
}
}
+ // Check any additional names that we have.
+ const AddlRegName *AddlNames;
+ unsigned NumAddlNames;
+ getGCCAddlRegNames(AddlNames, NumAddlNames);
+ for (unsigned i = 0; i < NumAddlNames; i++)
+ for (unsigned j = 0; j < llvm::array_lengthof(AddlNames[i].Names); j++) {
+ if (!AddlNames[i].Names[j])
+ break;
+ // Make sure the register that the additional name is for is within
+ // the bounds of the register names from above.
+ if (AddlNames[i].Names[j] == Name && AddlNames[i].RegNum < NumNames)
+ return Name;
+ }
+
// Now check aliases.
const GCCRegAlias *Aliases;
unsigned NumAliases;
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index dd167dca47b2..3518ea6f7986 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -84,14 +84,28 @@ static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts,
Builder.defineMacro("__MACH__");
Builder.defineMacro("OBJC_NEW_PROPERTIES");
- // __weak is always defined, for use in blocks and with objc pointers.
- Builder.defineMacro("__weak", "__attribute__((objc_gc(weak)))");
+ if (!Opts.ObjCAutoRefCount) {
+ // __weak is always defined, for use in blocks and with objc pointers.
+ Builder.defineMacro("__weak", "__attribute__((objc_gc(weak)))");
- // Darwin defines __strong even in C mode (just to nothing).
- if (!Opts.ObjC1 || Opts.getGCMode() == LangOptions::NonGC)
- Builder.defineMacro("__strong", "");
- else
- Builder.defineMacro("__strong", "__attribute__((objc_gc(strong)))");
+ // Darwin defines __strong even in C mode (just to nothing).
+ if (Opts.getGCMode() != LangOptions::NonGC)
+ Builder.defineMacro("__strong", "__attribute__((objc_gc(strong)))");
+ else
+ Builder.defineMacro("__strong", "");
+
+ // __unsafe_unretained is defined to nothing in non-ARC mode. We even
+ // allow this in C, since one might have block pointers in structs that
+ // are used in pure C code and in Objective-C ARC.
+ Builder.defineMacro("__unsafe_unretained", "");
+
+ // The Objective-C bridged cast keywords are defined to nothing in non-ARC
+ // mode; then they become normal, C-style casts.
+ Builder.defineMacro("__bridge", "");
+ Builder.defineMacro("__bridge_transfer", "");
+ Builder.defineMacro("__bridge_retained", "");
+ Builder.defineMacro("__bridge_retain", "");
+ }
if (Opts.Static)
Builder.defineMacro("__STATIC__");
@@ -168,14 +182,15 @@ class DarwinTargetInfo : public OSTargetInfo<Target> {
protected:
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
MacroBuilder &Builder) const {
- getDarwinDefines(Builder, Opts, Triple, this->PlatformName,
+ getDarwinDefines(Builder, Opts, Triple, this->PlatformName,
this->PlatformMinVersion);
}
public:
DarwinTargetInfo(const std::string& triple) :
OSTargetInfo<Target>(triple) {
- this->TLSSupported = llvm::Triple(triple).getDarwinMajorNumber() > 10;
+ llvm::Triple T = llvm::Triple(triple);
+ this->TLSSupported = T.isMacOSX() && !T.isMacOSXVersionLT(10,7);
this->MCountName = "\01mcount";
}
@@ -512,7 +527,6 @@ class PPCTargetInfo : public TargetInfo {
static const Builtin::Info BuiltinInfo[];
static const char * const GCCRegNames[];
static const TargetInfo::GCCRegAlias GCCRegAliases[];
-
public:
PPCTargetInfo(const std::string& triple) : TargetInfo(triple) {}
@@ -633,9 +647,9 @@ public:
};
const Builtin::Info PPCTargetInfo::BuiltinInfo[] = {
-#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES, false },
+#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES },
#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER,\
- ALL_LANGUAGES, false },
+ ALL_LANGUAGES },
#include "clang/Basic/BuiltinsPPC.def"
};
@@ -660,7 +674,8 @@ void PPCTargetInfo::getTargetDefines(const LangOptions &Opts,
}
// Target properties.
- Builder.defineMacro("_BIG_ENDIAN");
+ if (getTriple().getOS() != llvm::Triple::NetBSD)
+ Builder.defineMacro("_BIG_ENDIAN");
Builder.defineMacro("__BIG_ENDIAN__");
// Subtarget options.
@@ -788,8 +803,14 @@ public:
DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
"i64:64:64-f32:32:32-f64:64:64-v128:128:128-n32";
- if (getTriple().getOS() == llvm::Triple::FreeBSD)
- SizeType = UnsignedInt;
+ switch (getTriple().getOS()) {
+ case llvm::Triple::FreeBSD:
+ case llvm::Triple::NetBSD:
+ SizeType = UnsignedInt;
+ break;
+ default:
+ break;
+ }
}
virtual const char *getVAListDeclaration() const {
@@ -890,9 +911,9 @@ namespace {
};
const Builtin::Info PTXTargetInfo::BuiltinInfo[] = {
-#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES, false },
+#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES },
#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER,\
- ALL_LANGUAGES, false },
+ ALL_LANGUAGES },
#include "clang/Basic/BuiltinsPTX.def"
};
@@ -1058,49 +1079,49 @@ void MBlazeTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases,
namespace {
// Namespace for x86 abstract base class
const Builtin::Info BuiltinInfo[] = {
-#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES, false },
+#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES },
#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER,\
- ALL_LANGUAGES, false },
+ ALL_LANGUAGES },
#include "clang/Basic/BuiltinsX86.def"
};
static const char* const GCCRegNames[] = {
"ax", "dx", "cx", "bx", "si", "di", "bp", "sp",
"st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)",
- "argp", "flags", "fspr", "dirflag", "frame",
+ "argp", "flags", "fpcr", "fpsr", "dirflag", "frame",
"xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
"mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
- "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"
+ "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15",
};
-const TargetInfo::GCCRegAlias GCCRegAliases[] = {
- { { "al", "ah", "eax", "rax" }, "ax" },
- { { "bl", "bh", "ebx", "rbx" }, "bx" },
- { { "cl", "ch", "ecx", "rcx" }, "cx" },
- { { "dl", "dh", "edx", "rdx" }, "dx" },
- { { "esi", "rsi" }, "si" },
- { { "edi", "rdi" }, "di" },
- { { "esp", "rsp" }, "sp" },
- { { "ebp", "rbp" }, "bp" },
+const TargetInfo::AddlRegName AddlRegNames[] = {
+ { { "al", "ah", "eax", "rax" }, 0 },
+ { { "bl", "bh", "ebx", "rbx" }, 3 },
+ { { "cl", "ch", "ecx", "rcx" }, 2 },
+ { { "dl", "dh", "edx", "rdx" }, 1 },
+ { { "esi", "rsi" }, 4 },
+ { { "edi", "rdi" }, 5 },
+ { { "esp", "rsp" }, 7 },
+ { { "ebp", "rbp" }, 6 },
};
// X86 target abstract base class; x86-32 and x86-64 are very close, so
// most of the implementation can be shared.
class X86TargetInfo : public TargetInfo {
enum X86SSEEnum {
- NoMMXSSE, MMX, SSE1, SSE2, SSE3, SSSE3, SSE41, SSE42
+ NoSSE, SSE1, SSE2, SSE3, SSSE3, SSE41, SSE42
} SSELevel;
- enum AMD3DNowEnum {
- NoAMD3DNow, AMD3DNow, AMD3DNowAthlon
- } AMD3DNowLevel;
+ enum MMX3DNowEnum {
+ NoMMX3DNow, MMX, AMD3DNow, AMD3DNowAthlon
+ } MMX3DNowLevel;
bool HasAES;
bool HasAVX;
public:
X86TargetInfo(const std::string& triple)
- : TargetInfo(triple), SSELevel(NoMMXSSE), AMD3DNowLevel(NoAMD3DNow),
+ : TargetInfo(triple), SSELevel(NoSSE), MMX3DNowLevel(NoMMX3DNow),
HasAES(false), HasAVX(false) {
LongDoubleFormat = &llvm::APFloat::x87DoubleExtended;
}
@@ -1116,8 +1137,13 @@ public:
}
virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
unsigned &NumAliases) const {
- Aliases = GCCRegAliases;
- NumAliases = llvm::array_lengthof(GCCRegAliases);
+ Aliases = 0;
+ NumAliases = 0;
+ }
+ virtual void getGCCAddlRegNames(const AddlRegName *&Names,
+ unsigned &NumNames) const {
+ Names = AddlRegNames;
+ NumNames = llvm::array_lengthof(AddlRegNames);
}
virtual bool validateAsmConstraint(const char *&Name,
TargetInfo::ConstraintInfo &info) const;
@@ -1133,6 +1159,9 @@ public:
virtual void getDefaultFeatures(const std::string &CPU,
llvm::StringMap<bool> &Features) const;
virtual void HandleTargetFeatures(std::vector<std::string> &Features);
+ virtual const char* getABI() const {
+ return MMX3DNowLevel == NoMMX3DNow ? "no-mmx" : "";
+ }
};
void X86TargetInfo::getDefaultFeatures(const std::string &CPU,
@@ -1164,31 +1193,38 @@ void X86TargetInfo::getDefaultFeatures(const std::string &CPU,
;
else if (CPU == "pentium-mmx" || CPU == "pentium2")
setFeatureEnabled(Features, "mmx", true);
- else if (CPU == "pentium3")
+ else if (CPU == "pentium3") {
+ setFeatureEnabled(Features, "mmx", true);
setFeatureEnabled(Features, "sse", true);
- else if (CPU == "pentium-m" || CPU == "pentium4" || CPU == "x86-64")
+ } else if (CPU == "pentium-m" || CPU == "pentium4" || CPU == "x86-64") {
+ setFeatureEnabled(Features, "mmx", true);
setFeatureEnabled(Features, "sse2", true);
- else if (CPU == "yonah" || CPU == "prescott" || CPU == "nocona")
+ } else if (CPU == "yonah" || CPU == "prescott" || CPU == "nocona") {
+ setFeatureEnabled(Features, "mmx", true);
setFeatureEnabled(Features, "sse3", true);
- else if (CPU == "core2")
+ } else if (CPU == "core2") {
+ setFeatureEnabled(Features, "mmx", true);
setFeatureEnabled(Features, "ssse3", true);
- else if (CPU == "penryn") {
+ } else if (CPU == "penryn") {
+ setFeatureEnabled(Features, "mmx", true);
setFeatureEnabled(Features, "sse4", true);
Features["sse42"] = false;
- } else if (CPU == "atom")
+ } else if (CPU == "atom") {
+ setFeatureEnabled(Features, "mmx", true);
setFeatureEnabled(Features, "sse3", true);
- else if (CPU == "corei7") {
+ } else if (CPU == "corei7") {
+ setFeatureEnabled(Features, "mmx", true);
setFeatureEnabled(Features, "sse4", true);
setFeatureEnabled(Features, "aes", true);
} else if (CPU == "corei7-avx") {
+ setFeatureEnabled(Features, "mmx", true);
setFeatureEnabled(Features, "sse4", true);
setFeatureEnabled(Features, "aes", true);
-// setFeatureEnabled(Features, "avx", true);
+ //setFeatureEnabled(Features, "avx", true);
} else if (CPU == "k6" || CPU == "winchip-c6")
setFeatureEnabled(Features, "mmx", true);
else if (CPU == "k6-2" || CPU == "k6-3" || CPU == "athlon" ||
CPU == "athlon-tbird" || CPU == "winchip2" || CPU == "c3") {
- setFeatureEnabled(Features, "mmx", true);
setFeatureEnabled(Features, "3dnow", true);
} else if (CPU == "athlon-4" || CPU == "athlon-xp" || CPU == "athlon-mp") {
setFeatureEnabled(Features, "sse", true);
@@ -1200,8 +1236,10 @@ void X86TargetInfo::getDefaultFeatures(const std::string &CPU,
} else if (CPU == "k8-sse3") {
setFeatureEnabled(Features, "sse3", true);
setFeatureEnabled(Features, "3dnowa", true);
- } else if (CPU == "c3-2")
+ } else if (CPU == "c3-2") {
+ setFeatureEnabled(Features, "mmx", true);
setFeatureEnabled(Features, "sse", true);
+ }
}
bool X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
@@ -1217,34 +1255,31 @@ bool X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
if (Name == "mmx")
Features["mmx"] = true;
else if (Name == "sse")
- Features["mmx"] = Features["sse"] = true;
+ Features["sse"] = true;
else if (Name == "sse2")
- Features["mmx"] = Features["sse"] = Features["sse2"] = true;
+ Features["sse"] = Features["sse2"] = true;
else if (Name == "sse3")
- Features["mmx"] = Features["sse"] = Features["sse2"] =
- Features["sse3"] = true;
+ Features["sse"] = Features["sse2"] = Features["sse3"] = true;
else if (Name == "ssse3")
- Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
+ Features["sse"] = Features["sse2"] = Features["sse3"] =
Features["ssse3"] = true;
else if (Name == "sse4" || Name == "sse4.2")
- Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
+ Features["sse"] = Features["sse2"] = Features["sse3"] =
Features["ssse3"] = Features["sse41"] = Features["sse42"] = true;
else if (Name == "sse4.1")
- Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
+ Features["sse"] = Features["sse2"] = Features["sse3"] =
Features["ssse3"] = Features["sse41"] = true;
else if (Name == "3dnow")
- Features["3dnowa"] = true;
+ Features["mmx"] = Features["3dnow"] = true;
else if (Name == "3dnowa")
- Features["3dnow"] = Features["3dnowa"] = true;
+ Features["mmx"] = Features["3dnow"] = Features["3dnowa"] = true;
else if (Name == "aes")
Features["aes"] = true;
else if (Name == "avx")
Features["avx"] = true;
} else {
if (Name == "mmx")
- Features["mmx"] = Features["3dnow"] = Features["3dnowa"] =
- Features["sse"] = Features["sse2"] = Features["sse3"] =
- Features["ssse3"] = Features["sse41"] = Features["sse42"] = false;
+ Features["mmx"] = Features["3dnow"] = Features["3dnowa"] = false;
else if (Name == "sse")
Features["sse"] = Features["sse2"] = Features["sse3"] =
Features["ssse3"] = Features["sse41"] = Features["sse42"] = false;
@@ -1302,18 +1337,25 @@ void X86TargetInfo::HandleTargetFeatures(std::vector<std::string> &Features) {
.Case("sse3", SSE3)
.Case("sse2", SSE2)
.Case("sse", SSE1)
- .Case("mmx", MMX)
- .Default(NoMMXSSE);
+ .Default(NoSSE);
SSELevel = std::max(SSELevel, Level);
- AMD3DNowEnum ThreeDNowLevel =
- llvm::StringSwitch<AMD3DNowEnum>(Features[i].substr(1))
+ MMX3DNowEnum ThreeDNowLevel =
+ llvm::StringSwitch<MMX3DNowEnum>(Features[i].substr(1))
.Case("3dnowa", AMD3DNowAthlon)
.Case("3dnow", AMD3DNow)
- .Default(NoAMD3DNow);
+ .Case("mmx", MMX)
+ .Default(NoMMX3DNow);
- AMD3DNowLevel = std::max(AMD3DNowLevel, ThreeDNowLevel);
+ MMX3DNowLevel = std::max(MMX3DNowLevel, ThreeDNowLevel);
}
+
+ // Don't tell the backend if we're turning off mmx; it will end up disabling
+ // SSE, which we don't want.
+ std::vector<std::string>::iterator it;
+ it = std::find(Features.begin(), Features.end(), "-mmx");
+ if (it != Features.end())
+ Features.erase(it);
}
/// X86TargetInfo::getTargetDefines - Return a set of the X86-specific #defines
@@ -1368,9 +1410,7 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
case SSE1:
Builder.defineMacro("__SSE__");
Builder.defineMacro("__SSE_MATH__"); // -mfp-math=sse always implied.
- case MMX:
- Builder.defineMacro("__MMX__");
- case NoMMXSSE:
+ case NoSSE:
break;
}
@@ -1392,12 +1432,14 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
}
// Each case falls through to the previous one here.
- switch (AMD3DNowLevel) {
+ switch (MMX3DNowLevel) {
case AMD3DNowAthlon:
Builder.defineMacro("__3dNOW_A__");
case AMD3DNow:
Builder.defineMacro("__3dNOW__");
- case NoAMD3DNow:
+ case MMX:
+ Builder.defineMacro("__MMX__");
+ case NoMMX3DNow:
break;
}
}
@@ -1647,6 +1689,65 @@ public:
};
} // end anonymous namespace
+// RTEMS Target
+template<typename Target>
+class RTEMSTargetInfo : public OSTargetInfo<Target> {
+protected:
+ virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const {
+ // RTEMS defines; list based off of gcc output
+
+ // FIXME: Move version number handling to llvm::Triple.
+ llvm::StringRef Release = Triple.getOSName().substr(strlen("rtems"), 1);
+
+ Builder.defineMacro("__rtems__");
+ Builder.defineMacro("__ELF__");
+ }
+public:
+ RTEMSTargetInfo(const std::string &triple)
+ : OSTargetInfo<Target>(triple) {
+ this->UserLabelPrefix = "";
+
+ llvm::Triple Triple(triple);
+ switch (Triple.getArch()) {
+ default:
+ case llvm::Triple::x86:
+ // this->MCountName = ".mcount";
+ break;
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ // this->MCountName = "_mcount";
+ break;
+ case llvm::Triple::arm:
+ // this->MCountName = "__mcount";
+ break;
+ }
+
+ }
+};
+
+namespace {
+// x86-32 RTEMS target
+class RTEMSX86_32TargetInfo : public X86_32TargetInfo {
+public:
+ RTEMSX86_32TargetInfo(const std::string& triple)
+ : X86_32TargetInfo(triple) {
+ SizeType = UnsignedLong;
+ IntPtrType = SignedLong;
+ PtrDiffType = SignedLong;
+ this->UserLabelPrefix = "";
+ }
+ virtual void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ X86_32TargetInfo::getTargetDefines(Opts, Builder);
+ Builder.defineMacro("__INTEL__");
+ Builder.defineMacro("__rtems__");
+ }
+};
+} // end anonymous namespace
+
namespace {
// x86-64 generic target
class X86_64TargetInfo : public X86TargetInfo {
@@ -1861,7 +1962,7 @@ public:
// Thumb1 add sp, #imm requires the immediate value be multiple of 4,
// so set preferred for small types to 32.
DescriptionString = ("e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-"
- "i64:32:32-f32:32:32-f64:32:32-"
+ "i64:32:64-f32:32:32-f64:32:64-"
"v64:32:64-v128:32:128-a0:0:32-n32");
} else {
DescriptionString = ("e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
@@ -1882,11 +1983,6 @@ public:
void getDefaultFeatures(const std::string &CPU,
llvm::StringMap<bool> &Features) const {
- // FIXME: This should not be here.
- Features["vfp2"] = false;
- Features["vfp3"] = false;
- Features["neon"] = false;
-
if (CPU == "arm1136jf-s" || CPU == "arm1176jzf-s" || CPU == "mpcore")
Features["vfp2"] = true;
else if (CPU == "cortex-a8" || CPU == "cortex-a9")
@@ -1896,12 +1992,8 @@ public:
virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features,
const std::string &Name,
bool Enabled) const {
- if (Name == "soft-float" || Name == "soft-float-abi") {
- Features[Name] = Enabled;
- } else if (Name == "vfp2" || Name == "vfp3" || Name == "neon") {
- // These effectively are a single option, reset them when any is enabled.
- if (Enabled)
- Features["vfp2"] = Features["vfp3"] = Features["neon"] = false;
+ if (Name == "soft-float" || Name == "soft-float-abi" ||
+ Name == "vfp2" || Name == "vfp3" || Name == "neon") {
Features[Name] = Enabled;
} else
return false;
@@ -2042,6 +2134,12 @@ public:
case 'q': // ...ARMV4 ldrsb
case 'v': // ...VFP load/store (reg+constant offset)
case 'y': // ...iWMMXt load/store
+ case 't': // address valid for load/store opaque types wider
+ // than 128-bits
+ case 'n': // valid address for Neon doubleword vector load/store
+ case 'm': // valid address for Neon element and structure load/store
+ case 's': // valid address for non-offset loads/stores of quad-word
+ // values in four ARM registers
Info.setAllowsMemory();
Name++;
return true;
@@ -2049,14 +2147,16 @@ public:
}
return false;
}
- std::string
- virtual convertConstraint(const char *&Constraint) const {
+ virtual std::string convertConstraint(const char *&Constraint) const {
std::string R;
switch (*Constraint) {
case 'U': // Two-character constraint; add "^" hint for later parsing.
R = std::string("^") + std::string(Constraint, 2);
Constraint++;
break;
+ case 'p': // 'p' should be translated to 'r' by default.
+ R = std::string("r");
+ break;
default:
return std::string(1, *Constraint);
}
@@ -2124,9 +2224,9 @@ void ARMTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases,
}
const Builtin::Info ARMTargetInfo::BuiltinInfo[] = {
-#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES, false },
+#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES },
#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER,\
- ALL_LANGUAGES, false },
+ ALL_LANGUAGES },
#include "clang/Basic/BuiltinsARM.def"
};
} // end anonymous namespace.
@@ -2727,45 +2827,81 @@ static TargetInfo *AllocateTarget(const std::string &T) {
return new LinuxTargetInfo<ARMTargetInfo>(T);
case llvm::Triple::FreeBSD:
return new FreeBSDTargetInfo<ARMTargetInfo>(T);
+ case llvm::Triple::NetBSD:
+ return new NetBSDTargetInfo<ARMTargetInfo>(T);
+ case llvm::Triple::RTEMS:
+ return new RTEMSTargetInfo<ARMTargetInfo>(T);
default:
return new ARMTargetInfo(T);
}
case llvm::Triple::bfin:
+ if ( os == llvm::Triple::RTEMS )
+ return new RTEMSTargetInfo<BlackfinTargetInfo>(T);
return new BlackfinTargetInfo(T);
case llvm::Triple::msp430:
return new MSP430TargetInfo(T);
case llvm::Triple::mips:
- if (os == llvm::Triple::Psp)
+ switch (os) {
+ case llvm::Triple::Psp:
return new PSPTargetInfo<MipsTargetInfo>(T);
- if (os == llvm::Triple::Linux)
+ case llvm::Triple::Linux:
return new LinuxTargetInfo<MipsTargetInfo>(T);
- return new MipsTargetInfo(T);
+ case llvm::Triple::RTEMS:
+ return new RTEMSTargetInfo<MipsTargetInfo>(T);
+ case llvm::Triple::FreeBSD:
+ return new FreeBSDTargetInfo<MipsTargetInfo>(T);
+ case llvm::Triple::NetBSD:
+ return new NetBSDTargetInfo<MipsTargetInfo>(T);
+ default:
+ return new MipsTargetInfo(T);
+ }
case llvm::Triple::mipsel:
- if (os == llvm::Triple::Psp)
+ switch (os) {
+ case llvm::Triple::Psp:
return new PSPTargetInfo<MipselTargetInfo>(T);
- if (os == llvm::Triple::Linux)
+ case llvm::Triple::Linux:
return new LinuxTargetInfo<MipselTargetInfo>(T);
- return new MipselTargetInfo(T);
+ case llvm::Triple::RTEMS:
+ return new RTEMSTargetInfo<MipselTargetInfo>(T);
+ case llvm::Triple::FreeBSD:
+ return new FreeBSDTargetInfo<MipselTargetInfo>(T);
+ case llvm::Triple::NetBSD:
+ return new NetBSDTargetInfo<MipselTargetInfo>(T);
+ default:
+ return new MipsTargetInfo(T);
+ }
case llvm::Triple::ppc:
if (Triple.isOSDarwin())
return new DarwinPPC32TargetInfo(T);
- else if (os == llvm::Triple::FreeBSD)
+ switch (os) {
+ case llvm::Triple::FreeBSD:
return new FreeBSDTargetInfo<PPC32TargetInfo>(T);
- return new PPC32TargetInfo(T);
+ case llvm::Triple::NetBSD:
+ return new NetBSDTargetInfo<PPC32TargetInfo>(T);
+ case llvm::Triple::RTEMS:
+ return new RTEMSTargetInfo<PPC32TargetInfo>(T);
+ default:
+ return new PPC32TargetInfo(T);
+ }
case llvm::Triple::ppc64:
if (Triple.isOSDarwin())
return new DarwinPPC64TargetInfo(T);
- else if (os == llvm::Triple::Lv2)
+ switch (os) {
+ case llvm::Triple::Lv2:
return new PS3PPUTargetInfo<PPC64TargetInfo>(T);
- else if (os == llvm::Triple::FreeBSD)
+ case llvm::Triple::FreeBSD:
return new FreeBSDTargetInfo<PPC64TargetInfo>(T);
- return new PPC64TargetInfo(T);
+ case llvm::Triple::NetBSD:
+ return new NetBSDTargetInfo<PPC64TargetInfo>(T);
+ default:
+ return new PPC64TargetInfo(T);
+ }
case llvm::Triple::ptx32:
return new PTX32TargetInfo(T);
@@ -2776,11 +2912,18 @@ static TargetInfo *AllocateTarget(const std::string &T) {
return new MBlazeTargetInfo(T);
case llvm::Triple::sparc:
- if (os == llvm::Triple::AuroraUX)
+ switch (os) {
+ case llvm::Triple::AuroraUX:
return new AuroraUXSparcV8TargetInfo(T);
- if (os == llvm::Triple::Solaris)
+ case llvm::Triple::Solaris:
return new SolarisSparcV8TargetInfo(T);
- return new SparcV8TargetInfo(T);
+ case llvm::Triple::NetBSD:
+ return new NetBSDTargetInfo<SparcV8TargetInfo>(T);
+ case llvm::Triple::RTEMS:
+ return new RTEMSTargetInfo<SparcV8TargetInfo>(T);
+ default:
+ return new SparcV8TargetInfo(T);
+ }
// FIXME: Need a real SPU target.
case llvm::Triple::cellspu:
@@ -2821,6 +2964,8 @@ static TargetInfo *AllocateTarget(const std::string &T) {
return new VisualStudioWindowsX86_32TargetInfo(T);
case llvm::Triple::Haiku:
return new HaikuX86_32TargetInfo(T);
+ case llvm::Triple::RTEMS:
+ return new RTEMSX86_32TargetInfo(T);
default:
return new X86_32TargetInfo(T);
}
@@ -2910,7 +3055,8 @@ TargetInfo *TargetInfo::CreateTargetInfo(Diagnostic &Diags,
Opts.Features.clear();
for (llvm::StringMap<bool>::const_iterator it = Features.begin(),
ie = Features.end(); it != ie; ++it)
- Opts.Features.push_back(std::string(it->second ? "+" : "-") + it->first());
+ Opts.Features.push_back(std::string(it->second ? "+" : "-") +
+ it->first().str());
Target->HandleTargetFeatures(Opts.Features);
return Target.take();
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index b4574344bc5f..7b46c6040a9c 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -7,6 +7,7 @@ add_subdirectory(Sema)
add_subdirectory(CodeGen)
add_subdirectory(Analysis)
add_subdirectory(Rewrite)
+add_subdirectory(ARCMigrate)
add_subdirectory(Driver)
add_subdirectory(Serialization)
add_subdirectory(Frontend)
diff --git a/lib/CodeGen/ABIInfo.h b/lib/CodeGen/ABIInfo.h
index ce1039849b7c..138123816c3e 100644
--- a/lib/CodeGen/ABIInfo.h
+++ b/lib/CodeGen/ABIInfo.h
@@ -68,22 +68,22 @@ namespace clang {
private:
Kind TheKind;
- llvm::PATypeHolder TypeData;
+ llvm::Type *TypeData;
unsigned UIntData;
bool BoolData0;
bool BoolData1;
- ABIArgInfo(Kind K, const llvm::Type *TD=0,
+ ABIArgInfo(Kind K, llvm::Type *TD=0,
unsigned UI=0, bool B0 = false, bool B1 = false)
: TheKind(K), TypeData(TD), UIntData(UI), BoolData0(B0), BoolData1(B1) {}
public:
ABIArgInfo() : TheKind(Direct), TypeData(0), UIntData(0) {}
- static ABIArgInfo getDirect(const llvm::Type *T = 0, unsigned Offset = 0) {
+ static ABIArgInfo getDirect(llvm::Type *T = 0, unsigned Offset = 0) {
return ABIArgInfo(Direct, T, Offset);
}
- static ABIArgInfo getExtend(const llvm::Type *T = 0) {
+ static ABIArgInfo getExtend(llvm::Type *T = 0) {
return ABIArgInfo(Extend, T, 0);
}
static ABIArgInfo getIgnore() {
@@ -113,12 +113,12 @@ namespace clang {
assert((isDirect() || isExtend()) && "Not a direct or extend kind");
return UIntData;
}
- const llvm::Type *getCoerceToType() const {
+ llvm::Type *getCoerceToType() const {
assert(canHaveCoerceToType() && "Invalid kind!");
return TypeData;
}
- void setCoerceToType(const llvm::Type *T) {
+ void setCoerceToType(llvm::Type *T) {
assert(canHaveCoerceToType() && "Invalid kind!");
TypeData = T;
}
diff --git a/lib/CodeGen/BackendUtil.cpp b/lib/CodeGen/BackendUtil.cpp
index 01d15ff7f7fd..85f42db81f59 100644
--- a/lib/CodeGen/BackendUtil.cpp
+++ b/lib/CodeGen/BackendUtil.cpp
@@ -10,6 +10,7 @@
#include "clang/CodeGen/BackendUtil.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/TargetOptions.h"
+#include "clang/Basic/LangOptions.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "llvm/Module.h"
@@ -18,13 +19,13 @@
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/CodeGen/RegAllocRegistry.h"
#include "llvm/CodeGen/SchedulerRegistry.h"
+#include "llvm/MC/SubtargetFeature.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/PassManagerBuilder.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Target/SubtargetFeature.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
@@ -39,6 +40,7 @@ class EmitAssemblyHelper {
Diagnostic &Diags;
const CodeGenOptions &CodeGenOpts;
const TargetOptions &TargetOpts;
+ const LangOptions &LangOpts;
Module *TheModule;
Timer CodeGenerationTime;
@@ -82,8 +84,9 @@ private:
public:
EmitAssemblyHelper(Diagnostic &_Diags,
const CodeGenOptions &CGOpts, const TargetOptions &TOpts,
+ const LangOptions &LOpts,
Module *M)
- : Diags(_Diags), CodeGenOpts(CGOpts), TargetOpts(TOpts),
+ : Diags(_Diags), CodeGenOpts(CGOpts), TargetOpts(TOpts), LangOpts(LOpts),
TheModule(M), CodeGenerationTime("Code Generation Time"),
CodeGenPasses(0), PerModulePasses(0), PerFunctionPasses(0) {}
@@ -98,6 +101,16 @@ public:
}
+static void addObjCARCExpandPass(const PassManagerBuilder &Builder, PassManagerBase &PM) {
+ if (Builder.OptLevel > 0)
+ PM.add(createObjCARCExpandPass());
+}
+
+static void addObjCARCOptPass(const PassManagerBuilder &Builder, PassManagerBase &PM) {
+ if (Builder.OptLevel > 0)
+ PM.add(createObjCARCOptPass());
+}
+
void EmitAssemblyHelper::CreatePasses() {
unsigned OptLevel = CodeGenOpts.OptimizationLevel;
CodeGenOptions::InliningMethod Inlining = CodeGenOpts.Inlining;
@@ -116,6 +129,14 @@ void EmitAssemblyHelper::CreatePasses() {
PMBuilder.DisableSimplifyLibCalls = !CodeGenOpts.SimplifyLibCalls;
PMBuilder.DisableUnitAtATime = !CodeGenOpts.UnitAtATime;
PMBuilder.DisableUnrollLoops = !CodeGenOpts.UnrollLoops;
+
+ // In ObjC ARC mode, add the main ARC optimization passes.
+ if (LangOpts.ObjCAutoRefCount) {
+ PMBuilder.addExtension(PassManagerBuilder::EP_EarlyAsPossible,
+ addObjCARCExpandPass);
+ PMBuilder.addExtension(PassManagerBuilder::EP_ScalarOptimizerLate,
+ addObjCARCOptPass);
+ }
// Figure out TargetLibraryInfo.
Triple TargetTriple(TheModule->getTargetTriple());
@@ -258,16 +279,16 @@ bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action,
const_cast<char **>(&BackendArgs[0]));
std::string FeaturesStr;
- if (TargetOpts.CPU.size() || TargetOpts.Features.size()) {
+ if (TargetOpts.Features.size()) {
SubtargetFeatures Features;
- Features.setCPU(TargetOpts.CPU);
for (std::vector<std::string>::const_iterator
it = TargetOpts.Features.begin(),
ie = TargetOpts.Features.end(); it != ie; ++it)
Features.AddFeature(*it);
FeaturesStr = Features.getString();
}
- TargetMachine *TM = TheTarget->createTargetMachine(Triple, FeaturesStr);
+ TargetMachine *TM = TheTarget->createTargetMachine(Triple, TargetOpts.CPU,
+ FeaturesStr);
if (CodeGenOpts.RelaxAll)
TM->setMCRelaxAll(true);
@@ -275,6 +296,8 @@ bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action,
TM->setMCSaveTempLabels(true);
if (CodeGenOpts.NoDwarf2CFIAsm)
TM->setMCUseCFI(false);
+ if (CodeGenOpts.NoExecStack)
+ TM->setMCNoExecStack(true);
// Create the code generator passes.
PassManager *PM = getCodeGenPasses();
@@ -295,6 +318,13 @@ bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action,
CGFT = TargetMachine::CGFT_Null;
else
assert(Action == Backend_EmitAssembly && "Invalid action!");
+
+ // Add ObjC ARC final-cleanup optimizations. This is done as part of the
+ // "codegen" passes so that it isn't run multiple times when there is
+ // inlining happening.
+ if (LangOpts.ObjCAutoRefCount)
+ PM->add(createObjCARCContractPass());
+
if (TM->addPassesToEmitFile(*PM, OS, CGFT, OptLevel,
/*DisableVerify=*/!CodeGenOpts.VerifyModule)) {
Diags.Report(diag::err_fe_unable_to_interface_with_target);
@@ -357,9 +387,11 @@ void EmitAssemblyHelper::EmitAssembly(BackendAction Action, raw_ostream *OS) {
}
void clang::EmitBackendOutput(Diagnostic &Diags, const CodeGenOptions &CGOpts,
- const TargetOptions &TOpts, Module *M,
+ const TargetOptions &TOpts,
+ const LangOptions &LOpts,
+ Module *M,
BackendAction Action, raw_ostream *OS) {
- EmitAssemblyHelper AsmHelper(Diags, CGOpts, TOpts, M);
+ EmitAssemblyHelper AsmHelper(Diags, CGOpts, TOpts, LOpts, M);
AsmHelper.EmitAssembly(Action, OS);
}
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index e5da703a61b2..9815d1d4ef4d 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -95,9 +95,7 @@ static llvm::Constant *buildBlockDescriptor(CodeGenModule &CGM,
else
elements.push_back(llvm::Constant::getNullValue(i8p));
- llvm::Constant *init =
- llvm::ConstantStruct::get(CGM.getLLVMContext(), elements.data(),
- elements.size(), false);
+ llvm::Constant *init = llvm::ConstantStruct::getAnon(elements);
llvm::GlobalVariable *global =
new llvm::GlobalVariable(CGM.getModule(), init->getType(), true,
@@ -166,11 +164,11 @@ namespace {
CharUnits Alignment;
CharUnits Size;
const BlockDecl::Capture *Capture; // null for 'this'
- const llvm::Type *Type;
+ llvm::Type *Type;
BlockLayoutChunk(CharUnits align, CharUnits size,
const BlockDecl::Capture *capture,
- const llvm::Type *type)
+ llvm::Type *type)
: Alignment(align), Size(size), Capture(capture), Type(type) {}
/// Tell the block info that this chunk has the given field index.
@@ -245,7 +243,7 @@ static CharUnits getLowBit(CharUnits v) {
}
static void initializeForBlockHeader(CodeGenModule &CGM, CGBlockInfo &info,
- llvm::SmallVectorImpl<const llvm::Type*> &elementTypes) {
+ llvm::SmallVectorImpl<llvm::Type*> &elementTypes) {
ASTContext &C = CGM.getContext();
// The header is basically a 'struct { void *; int; int; void *; void *; }'.
@@ -265,8 +263,8 @@ static void initializeForBlockHeader(CodeGenModule &CGM, CGBlockInfo &info,
info.BlockSize = headerSize;
assert(elementTypes.empty());
- const llvm::Type *i8p = CGM.getTypes().ConvertType(C.VoidPtrTy);
- const llvm::Type *intTy = CGM.getTypes().ConvertType(C.IntTy);
+ llvm::Type *i8p = CGM.getTypes().ConvertType(C.VoidPtrTy);
+ llvm::Type *intTy = CGM.getTypes().ConvertType(C.IntTy);
elementTypes.push_back(i8p);
elementTypes.push_back(intTy);
elementTypes.push_back(intTy);
@@ -282,7 +280,7 @@ static void computeBlockInfo(CodeGenModule &CGM, CGBlockInfo &info) {
ASTContext &C = CGM.getContext();
const BlockDecl *block = info.getBlockDecl();
- llvm::SmallVector<const llvm::Type*, 8> elementTypes;
+ llvm::SmallVector<llvm::Type*, 8> elementTypes;
initializeForBlockHeader(CGM, info, elementTypes);
if (!block->hasCaptures()) {
@@ -310,7 +308,7 @@ static void computeBlockInfo(CodeGenModule &CGM, CGBlockInfo &info) {
else
thisType = cast<CXXMethodDecl>(DC)->getThisType(C);
- const llvm::Type *llvmType = CGM.getTypes().ConvertType(thisType);
+ llvm::Type *llvmType = CGM.getTypes().ConvertType(thisType);
std::pair<CharUnits,CharUnits> tinfo
= CGM.getContext().getTypeInfoInChars(thisType);
maxFieldAlign = std::max(maxFieldAlign, tinfo.second);
@@ -330,7 +328,7 @@ static void computeBlockInfo(CodeGenModule &CGM, CGBlockInfo &info) {
// Just use void* instead of a pointer to the byref type.
QualType byRefPtrTy = C.VoidPtrTy;
- const llvm::Type *llvmType = CGM.getTypes().ConvertType(byRefPtrTy);
+ llvm::Type *llvmType = CGM.getTypes().ConvertType(byRefPtrTy);
std::pair<CharUnits,CharUnits> tinfo
= CGM.getContext().getTypeInfoInChars(byRefPtrTy);
maxFieldAlign = std::max(maxFieldAlign, tinfo.second);
@@ -347,13 +345,23 @@ static void computeBlockInfo(CodeGenModule &CGM, CGBlockInfo &info) {
continue;
}
- // Block pointers require copy/dispose.
- if (variable->getType()->isBlockPointerType()) {
- info.NeedsCopyDispose = true;
+ // If we have a lifetime qualifier, honor it for capture purposes.
+ // That includes *not* copying it if it's __unsafe_unretained.
+ if (Qualifiers::ObjCLifetime lifetime
+ = variable->getType().getObjCLifetime()) {
+ switch (lifetime) {
+ case Qualifiers::OCL_None: llvm_unreachable("impossible");
+ case Qualifiers::OCL_ExplicitNone:
+ case Qualifiers::OCL_Autoreleasing:
+ break;
+
+ case Qualifiers::OCL_Strong:
+ case Qualifiers::OCL_Weak:
+ info.NeedsCopyDispose = true;
+ }
- // So do Objective-C pointers.
- } else if (variable->getType()->isObjCObjectPointerType() ||
- C.isObjCNSObjectType(variable->getType())) {
+ // Block pointers require copy/dispose. So do Objective-C pointers.
+ } else if (variable->getType()->isObjCRetainableType()) {
info.NeedsCopyDispose = true;
// So do types that require non-trivial copy construction.
@@ -376,7 +384,7 @@ static void computeBlockInfo(CodeGenModule &CGM, CGBlockInfo &info) {
CharUnits align = C.getDeclAlign(variable);
maxFieldAlign = std::max(maxFieldAlign, align);
- const llvm::Type *llvmType =
+ llvm::Type *llvmType =
CGM.getTypes().ConvertTypeForMem(variable->getType());
layout.push_back(BlockLayoutChunk(align, size, &*ci, llvmType));
@@ -591,6 +599,11 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) {
// Otherwise, fake up a POD copy into the block field.
} else {
+ // Fake up a new variable so that EmitScalarInit doesn't think
+ // we're referring to the variable in its own initializer.
+ ImplicitParamDecl blockFieldPseudoVar(/*DC*/ 0, SourceLocation(),
+ /*name*/ 0, type);
+
// We use one of these or the other depending on whether the
// reference is nested.
DeclRefExpr notNested(const_cast<VarDecl*>(variable), type, VK_LValue,
@@ -603,15 +616,37 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) {
ImplicitCastExpr l2r(ImplicitCastExpr::OnStack, type, CK_LValueToRValue,
declRef, VK_RValue);
- EmitExprAsInit(&l2r, variable, blockField,
- getContext().getDeclAlign(variable),
+ EmitExprAsInit(&l2r, &blockFieldPseudoVar,
+ LValue::MakeAddr(blockField, type,
+ getContext().getDeclAlign(variable)
+ .getQuantity(),
+ getContext()),
/*captured by init*/ false);
}
// Push a destructor if necessary. The semantics for when this
// actually gets run are really obscure.
- if (!ci->isByRef() && CGM.getLangOptions().CPlusPlus)
- PushDestructorCleanup(type, blockField);
+ if (!ci->isByRef()) {
+ switch (QualType::DestructionKind dtorKind = type.isDestructedType()) {
+ case QualType::DK_none:
+ break;
+
+ // Block captures count as local values and have imprecise semantics.
+ // They also can't be arrays, so need to worry about that.
+ case QualType::DK_objc_strong_lifetime: {
+ // This local is a GCC and MSVC compiler workaround.
+ Destroyer *destroyer = &destroyARCStrongImprecise;
+ pushDestroy(getCleanupKind(dtorKind), blockField, type,
+ *destroyer, /*useEHCleanupForArray*/ false);
+ break;
+ }
+
+ case QualType::DK_objc_weak_lifetime:
+ case QualType::DK_cxx_destructor:
+ pushDestroy(dtorKind, blockField, type);
+ break;
+ }
+ }
}
// Cast to the converted block-pointer type, which happens (somewhat
@@ -624,11 +659,11 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) {
}
-const llvm::Type *CodeGenModule::getBlockDescriptorType() {
+llvm::Type *CodeGenModule::getBlockDescriptorType() {
if (BlockDescriptorType)
return BlockDescriptorType;
- const llvm::Type *UnsignedLongTy =
+ llvm::Type *UnsignedLongTy =
getTypes().ConvertType(getContext().UnsignedLongTy);
// struct __block_descriptor {
@@ -645,24 +680,20 @@ const llvm::Type *CodeGenModule::getBlockDescriptorType() {
// const char *signature; // the block signature
// const char *layout; // reserved
// };
- BlockDescriptorType = llvm::StructType::get(UnsignedLongTy->getContext(),
- UnsignedLongTy,
- UnsignedLongTy,
- NULL);
-
- getModule().addTypeName("struct.__block_descriptor",
- BlockDescriptorType);
+ BlockDescriptorType =
+ llvm::StructType::createNamed("struct.__block_descriptor",
+ UnsignedLongTy, UnsignedLongTy, NULL);
// Now form a pointer to that.
BlockDescriptorType = llvm::PointerType::getUnqual(BlockDescriptorType);
return BlockDescriptorType;
}
-const llvm::Type *CodeGenModule::getGenericBlockLiteralType() {
+llvm::Type *CodeGenModule::getGenericBlockLiteralType() {
if (GenericBlockLiteralType)
return GenericBlockLiteralType;
- const llvm::Type *BlockDescPtrTy = getBlockDescriptorType();
+ llvm::Type *BlockDescPtrTy = getBlockDescriptorType();
// struct __block_literal_generic {
// void *__isa;
@@ -671,16 +702,14 @@ const llvm::Type *CodeGenModule::getGenericBlockLiteralType() {
// void (*__invoke)(void *);
// struct __block_descriptor *__descriptor;
// };
- GenericBlockLiteralType = llvm::StructType::get(getLLVMContext(),
- VoidPtrTy,
- IntTy,
- IntTy,
- VoidPtrTy,
- BlockDescPtrTy,
- NULL);
-
- getModule().addTypeName("struct.__block_literal_generic",
- GenericBlockLiteralType);
+ GenericBlockLiteralType =
+ llvm::StructType::createNamed("struct.__block_literal_generic",
+ VoidPtrTy,
+ IntTy,
+ IntTy,
+ VoidPtrTy,
+ BlockDescPtrTy,
+ NULL);
return GenericBlockLiteralType;
}
@@ -822,9 +851,7 @@ static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM,
// Descriptor
fields[4] = buildBlockDescriptor(CGM, blockInfo);
- llvm::Constant *init =
- llvm::ConstantStruct::get(CGM.getLLVMContext(), fields, BlockHeaderSize,
- /*packed*/ false);
+ llvm::Constant *init = llvm::ConstantStruct::getAnon(fields);
llvm::GlobalVariable *literal =
new llvm::GlobalVariable(CGM.getModule(),
@@ -1023,8 +1050,6 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
-
-
llvm::Constant *
CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
ASTContext &C = getContext();
@@ -1084,21 +1109,40 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
if (capture.isConstant()) continue;
const Expr *copyExpr = ci->getCopyExpr();
- unsigned flags = 0;
+ BlockFieldFlags flags;
+
+ bool isARCWeakCapture = false;
if (copyExpr) {
assert(!ci->isByRef());
// don't bother computing flags
+
} else if (ci->isByRef()) {
flags = BLOCK_FIELD_IS_BYREF;
- if (type.isObjCGCWeak()) flags |= BLOCK_FIELD_IS_WEAK;
- } else if (type->isBlockPointerType()) {
- flags = BLOCK_FIELD_IS_BLOCK;
- } else if (type->isObjCObjectPointerType() || C.isObjCNSObjectType(type)) {
+ if (type.isObjCGCWeak())
+ flags |= BLOCK_FIELD_IS_WEAK;
+
+ } else if (type->isObjCRetainableType()) {
flags = BLOCK_FIELD_IS_OBJECT;
- }
+ if (type->isBlockPointerType())
+ flags = BLOCK_FIELD_IS_BLOCK;
+
+ // Special rules for ARC captures:
+ if (getLangOptions().ObjCAutoRefCount) {
+ Qualifiers qs = type.getQualifiers();
- if (!copyExpr && !flags) continue;
+ // Don't generate special copy logic for a captured object
+ // unless it's __strong or __weak.
+ if (!qs.hasStrongOrWeakObjCLifetime())
+ continue;
+
+ // Support __weak direct captures.
+ if (qs.getObjCLifetime() == Qualifiers::OCL_Weak)
+ isARCWeakCapture = true;
+ }
+ } else {
+ continue;
+ }
unsigned index = capture.getIndex();
llvm::Value *srcField = Builder.CreateStructGEP(src, index);
@@ -1107,12 +1151,14 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
// If there's an explicit copy expression, we do that.
if (copyExpr) {
EmitSynthesizedCXXCopyCtor(dstField, srcField, copyExpr);
+ } else if (isARCWeakCapture) {
+ EmitARCCopyWeak(dstField, srcField);
} else {
llvm::Value *srcValue = Builder.CreateLoad(srcField, "blockcopy.src");
srcValue = Builder.CreateBitCast(srcValue, VoidPtrTy);
llvm::Value *dstAddr = Builder.CreateBitCast(dstField, VoidPtrTy);
Builder.CreateCall3(CGM.getBlockObjectAssign(), dstAddr, srcValue,
- llvm::ConstantInt::get(Int32Ty, flags));
+ llvm::ConstantInt::get(Int32Ty, flags.getBitMask()));
}
}
@@ -1176,20 +1222,37 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
BlockFieldFlags flags;
const CXXDestructorDecl *dtor = 0;
+ bool isARCWeakCapture = false;
+
if (ci->isByRef()) {
flags = BLOCK_FIELD_IS_BYREF;
- if (type.isObjCGCWeak()) flags |= BLOCK_FIELD_IS_WEAK;
- } else if (type->isBlockPointerType()) {
- flags = BLOCK_FIELD_IS_BLOCK;
- } else if (type->isObjCObjectPointerType() || C.isObjCNSObjectType(type)) {
+ if (type.isObjCGCWeak())
+ flags |= BLOCK_FIELD_IS_WEAK;
+ } else if (const CXXRecordDecl *record = type->getAsCXXRecordDecl()) {
+ if (record->hasTrivialDestructor())
+ continue;
+ dtor = record->getDestructor();
+ } else if (type->isObjCRetainableType()) {
flags = BLOCK_FIELD_IS_OBJECT;
- } else if (C.getLangOptions().CPlusPlus) {
- if (const CXXRecordDecl *record = type->getAsCXXRecordDecl())
- if (!record->hasTrivialDestructor())
- dtor = record->getDestructor();
- }
+ if (type->isBlockPointerType())
+ flags = BLOCK_FIELD_IS_BLOCK;
- if (!dtor && flags.empty()) continue;
+ // Special rules for ARC captures.
+ if (getLangOptions().ObjCAutoRefCount) {
+ Qualifiers qs = type.getQualifiers();
+
+ // Don't generate special dispose logic for a captured object
+ // unless it's __strong or __weak.
+ if (!qs.hasStrongOrWeakObjCLifetime())
+ continue;
+
+ // Support __weak direct captures.
+ if (qs.getObjCLifetime() == Qualifiers::OCL_Weak)
+ isARCWeakCapture = true;
+ }
+ } else {
+ continue;
+ }
unsigned index = capture.getIndex();
llvm::Value *srcField = Builder.CreateStructGEP(src, index);
@@ -1198,6 +1261,10 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
if (dtor) {
PushDestructorCleanup(dtor, srcField);
+ // If this is a __weak capture, emit the release directly.
+ } else if (isARCWeakCapture) {
+ EmitARCDestroyWeak(srcField);
+
// Otherwise we call _Block_object_dispose. It wouldn't be too
// hard to just emit this as a cleanup if we wanted to make sure
// that things were done in reverse.
@@ -1251,6 +1318,55 @@ public:
}
};
+/// Emits the copy/dispose helpers for an ARC __block __weak variable.
+class ARCWeakByrefHelpers : public CodeGenModule::ByrefHelpers {
+public:
+ ARCWeakByrefHelpers(CharUnits alignment) : ByrefHelpers(alignment) {}
+
+ void emitCopy(CodeGenFunction &CGF, llvm::Value *destField,
+ llvm::Value *srcField) {
+ CGF.EmitARCMoveWeak(destField, srcField);
+ }
+
+ void emitDispose(CodeGenFunction &CGF, llvm::Value *field) {
+ CGF.EmitARCDestroyWeak(field);
+ }
+
+ void profileImpl(llvm::FoldingSetNodeID &id) const {
+ // 0 is distinguishable from all pointers and byref flags
+ id.AddInteger(0);
+ }
+};
+
+/// Emits the copy/dispose helpers for an ARC __block __strong variable
+/// that's not of block-pointer type.
+class ARCStrongByrefHelpers : public CodeGenModule::ByrefHelpers {
+public:
+ ARCStrongByrefHelpers(CharUnits alignment) : ByrefHelpers(alignment) {}
+
+ void emitCopy(CodeGenFunction &CGF, llvm::Value *destField,
+ llvm::Value *srcField) {
+ // Do a "move" by copying the value and then zeroing out the old
+ // variable.
+
+ llvm::Value *value = CGF.Builder.CreateLoad(srcField);
+ llvm::Value *null =
+ llvm::ConstantPointerNull::get(cast<llvm::PointerType>(value->getType()));
+ CGF.Builder.CreateStore(value, destField);
+ CGF.Builder.CreateStore(null, srcField);
+ }
+
+ void emitDispose(CodeGenFunction &CGF, llvm::Value *field) {
+ llvm::Value *value = CGF.Builder.CreateLoad(field);
+ CGF.EmitARCRelease(value, /*precise*/ false);
+ }
+
+ void profileImpl(llvm::FoldingSetNodeID &id) const {
+ // 1 is distinguishable from all pointers and byref flags
+ id.AddInteger(1);
+ }
+};
+
/// Emits the copy/dispose helpers for a __block variable with a
/// nontrivial copy constructor or destructor.
class CXXByrefHelpers : public CodeGenModule::ByrefHelpers {
@@ -1318,6 +1434,7 @@ generateByrefCopyHelper(CodeGenFunction &CGF,
SC_Static,
SC_None,
false, true);
+
CGF.StartFunction(FD, R, Fn, FI, args, SourceLocation());
if (byrefInfo.needsCopy()) {
@@ -1449,6 +1566,52 @@ CodeGenFunction::buildByrefHelpers(const llvm::StructType &byrefType,
return ::buildByrefHelpers(CGM, byrefType, byrefInfo);
}
+ // Otherwise, if we don't have a retainable type, there's nothing to do.
+ // that the runtime does extra copies.
+ if (!type->isObjCRetainableType()) return 0;
+
+ Qualifiers qs = type.getQualifiers();
+
+ // If we have lifetime, that dominates.
+ if (Qualifiers::ObjCLifetime lifetime = qs.getObjCLifetime()) {
+ assert(getLangOptions().ObjCAutoRefCount);
+
+ switch (lifetime) {
+ case Qualifiers::OCL_None: llvm_unreachable("impossible");
+
+ // These are just bits as far as the runtime is concerned.
+ case Qualifiers::OCL_ExplicitNone:
+ case Qualifiers::OCL_Autoreleasing:
+ return 0;
+
+ // Tell the runtime that this is ARC __weak, called by the
+ // byref routines.
+ case Qualifiers::OCL_Weak: {
+ ARCWeakByrefHelpers byrefInfo(emission.Alignment);
+ return ::buildByrefHelpers(CGM, byrefType, byrefInfo);
+ }
+
+ // ARC __strong __block variables need to be retained.
+ case Qualifiers::OCL_Strong:
+ // Block-pointers need to be _Block_copy'ed, so we let the
+ // runtime be in charge. But we can't use the code below
+ // because we don't want to set BYREF_CALLER, which will
+ // just make the runtime ignore us.
+ if (type->isBlockPointerType()) {
+ BlockFieldFlags flags = BLOCK_FIELD_IS_BLOCK;
+ ObjectByrefHelpers byrefInfo(emission.Alignment, flags);
+ return ::buildByrefHelpers(CGM, byrefType, byrefInfo);
+
+ // Otherwise, we transfer ownership of the retain from the stack
+ // to the heap.
+ } else {
+ ARCStrongByrefHelpers byrefInfo(emission.Alignment);
+ return ::buildByrefHelpers(CGM, byrefType, byrefInfo);
+ }
+ }
+ llvm_unreachable("fell out of lifetime switch!");
+ }
+
BlockFieldFlags flags;
if (type->isBlockPointerType()) {
flags |= BLOCK_FIELD_IS_BLOCK;
@@ -1502,15 +1665,17 @@ const llvm::Type *CodeGenFunction::BuildByRefType(const VarDecl *D) {
QualType Ty = D->getType();
- llvm::SmallVector<const llvm::Type *, 8> types;
+ llvm::SmallVector<llvm::Type *, 8> types;
- llvm::PATypeHolder ByRefTypeHolder = llvm::OpaqueType::get(getLLVMContext());
+ llvm::StructType *ByRefType =
+ llvm::StructType::createNamed(getLLVMContext(),
+ "struct.__block_byref_" + D->getNameAsString());
// void *__isa;
types.push_back(Int8PtrTy);
// void *__forwarding;
- types.push_back(llvm::PointerType::getUnqual(ByRefTypeHolder));
+ types.push_back(llvm::PointerType::getUnqual(ByRefType));
// int32_t __flags;
types.push_back(Int32Ty);
@@ -1545,7 +1710,7 @@ const llvm::Type *CodeGenFunction::BuildByRefType(const VarDecl *D) {
unsigned NumPaddingBytes = AlignedOffsetInBytes - CurrentOffsetInBytes;
if (NumPaddingBytes > 0) {
- const llvm::Type *Ty = llvm::Type::getInt8Ty(getLLVMContext());
+ llvm::Type *Ty = llvm::Type::getInt8Ty(getLLVMContext());
// FIXME: We need a sema error for alignment larger than the minimum of
// the maximal stack alignment and the alignment of malloc on the system.
if (NumPaddingBytes > 1)
@@ -1561,13 +1726,9 @@ const llvm::Type *CodeGenFunction::BuildByRefType(const VarDecl *D) {
// T x;
types.push_back(ConvertTypeForMem(Ty));
- const llvm::Type *T = llvm::StructType::get(getLLVMContext(), types, Packed);
-
- cast<llvm::OpaqueType>(ByRefTypeHolder.get())->refineAbstractTypeTo(T);
- CGM.getModule().addTypeName("struct.__block_byref_" + D->getNameAsString(),
- ByRefTypeHolder.get());
+ ByRefType->setBody(types, Packed);
- Info.first = ByRefTypeHolder.get();
+ Info.first = ByRefType;
Info.second = types.size() - 1;
@@ -1638,7 +1799,8 @@ namespace {
llvm::Value *Addr;
CallBlockRelease(llvm::Value *Addr) : Addr(Addr) {}
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
+ // Should we be passing FIELD_IS_WEAK here?
CGF.BuildBlockRelease(Addr, BLOCK_FIELD_IS_BYREF);
}
};
diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h
index 9bd18e5fde74..4d8dead2be8c 100644
--- a/lib/CodeGen/CGBlocks.h
+++ b/lib/CodeGen/CGBlocks.h
@@ -17,7 +17,6 @@
#include "CodeGenTypes.h"
#include "clang/AST/Type.h"
#include "llvm/Module.h"
-#include "llvm/ADT/SmallVector.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/Expr.h"
@@ -89,7 +88,7 @@ enum BlockFieldFlag_t {
variable */
BLOCK_FIELD_IS_WEAK = 0x10, /* declared __weak, only used in byref copy
helpers */
-
+ BLOCK_FIELD_IS_ARC = 0x40, /* field has ARC-specific semantics */
BLOCK_BYREF_CALLER = 128, /* called from __block (byref) copy/dispose
support routines */
BLOCK_BYREF_CURRENT_MAX = 256
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index 14bebaf3c1cb..1566bd9e6697 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -22,6 +22,7 @@
#include "clang/Basic/TargetBuiltins.h"
#include "llvm/Intrinsics.h"
#include "llvm/Target/TargetData.h"
+
using namespace clang;
using namespace CodeGen;
using namespace llvm;
@@ -37,8 +38,7 @@ static void EmitMemoryBarrier(CodeGenFunction &CGF,
StoreLoad ? True : False,
StoreStore ? True : False,
Device ? True : False };
- CGF.Builder.CreateCall(CGF.CGM.getIntrinsic(Intrinsic::memory_barrier),
- C, C + 5);
+ CGF.Builder.CreateCall(CGF.CGM.getIntrinsic(Intrinsic::memory_barrier), C);
}
/// Emit the conversions required to turn the given value into an
@@ -68,14 +68,14 @@ static Value *EmitFromInt(CodeGenFunction &CGF, llvm::Value *V,
// The atomic builtins are also full memory barriers. This is a utility for
// wrapping a call to the builtins with memory barriers.
static Value *EmitCallWithBarrier(CodeGenFunction &CGF, Value *Fn,
- Value **ArgBegin, Value **ArgEnd) {
+ ArrayRef<Value *> Args) {
// FIXME: We need a target hook for whether this applies to device memory or
// not.
bool Device = true;
// Create barriers both before and after the call.
EmitMemoryBarrier(CGF, true, true, true, true, Device);
- Value *Result = CGF.Builder.CreateCall(Fn, ArgBegin, ArgEnd);
+ Value *Result = CGF.Builder.CreateCall(Fn, Args);
EmitMemoryBarrier(CGF, true, true, true, true, Device);
return Result;
}
@@ -94,13 +94,13 @@ static RValue EmitBinaryAtomic(CodeGenFunction &CGF,
unsigned AddrSpace =
cast<llvm::PointerType>(DestPtr->getType())->getAddressSpace();
- const llvm::IntegerType *IntType =
+ llvm::IntegerType *IntType =
llvm::IntegerType::get(CGF.getLLVMContext(),
CGF.getContext().getTypeSize(T));
- const llvm::Type *IntPtrType = IntType->getPointerTo(AddrSpace);
+ llvm::Type *IntPtrType = IntType->getPointerTo(AddrSpace);
- const llvm::Type *IntrinsicTypes[2] = { IntType, IntPtrType };
- llvm::Value *AtomF = CGF.CGM.getIntrinsic(Id, IntrinsicTypes, 2);
+ llvm::Type *IntrinsicTypes[2] = { IntType, IntPtrType };
+ llvm::Value *AtomF = CGF.CGM.getIntrinsic(Id, IntrinsicTypes);
llvm::Value *Args[2];
Args[0] = CGF.Builder.CreateBitCast(DestPtr, IntPtrType);
@@ -108,7 +108,7 @@ static RValue EmitBinaryAtomic(CodeGenFunction &CGF,
const llvm::Type *ValueType = Args[1]->getType();
Args[1] = EmitToInt(CGF, Args[1], T, IntType);
- llvm::Value *Result = EmitCallWithBarrier(CGF, AtomF, Args, Args + 2);
+ llvm::Value *Result = EmitCallWithBarrier(CGF, AtomF, Args);
Result = EmitFromInt(CGF, Result, T, ValueType);
return RValue::get(Result);
}
@@ -129,13 +129,13 @@ static RValue EmitBinaryAtomicPost(CodeGenFunction &CGF,
unsigned AddrSpace =
cast<llvm::PointerType>(DestPtr->getType())->getAddressSpace();
- const llvm::IntegerType *IntType =
+ llvm::IntegerType *IntType =
llvm::IntegerType::get(CGF.getLLVMContext(),
CGF.getContext().getTypeSize(T));
- const llvm::Type *IntPtrType = IntType->getPointerTo(AddrSpace);
+ llvm::Type *IntPtrType = IntType->getPointerTo(AddrSpace);
- const llvm::Type *IntrinsicTypes[2] = { IntType, IntPtrType };
- llvm::Value *AtomF = CGF.CGM.getIntrinsic(Id, IntrinsicTypes, 2);
+ llvm::Type *IntrinsicTypes[2] = { IntType, IntPtrType };
+ llvm::Value *AtomF = CGF.CGM.getIntrinsic(Id, IntrinsicTypes);
llvm::Value *Args[2];
Args[1] = CGF.EmitScalarExpr(E->getArg(1));
@@ -143,7 +143,7 @@ static RValue EmitBinaryAtomicPost(CodeGenFunction &CGF,
Args[1] = EmitToInt(CGF, Args[1], T, IntType);
Args[0] = CGF.Builder.CreateBitCast(DestPtr, IntPtrType);
- llvm::Value *Result = EmitCallWithBarrier(CGF, AtomF, Args, Args + 2);
+ llvm::Value *Result = EmitCallWithBarrier(CGF, AtomF, Args);
Result = CGF.Builder.CreateBinOp(Op, Result, Args[1]);
Result = EmitFromInt(CGF, Result, T, ValueType);
return RValue::get(Result);
@@ -164,7 +164,8 @@ static Value *EmitFAbs(CodeGenFunction &CGF, Value *V, QualType ValTy) {
}
// The prototype is something that takes and returns whatever V's type is.
- llvm::FunctionType *FT = llvm::FunctionType::get(V->getType(), V->getType(),
+ llvm::Type *ArgTys[] = { V->getType() };
+ llvm::FunctionType *FT = llvm::FunctionType::get(V->getType(), ArgTys,
false);
llvm::Value *Fn = CGF.CGM.CreateRuntimeFunction(FT, FnName);
@@ -232,8 +233,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BI__builtin_ctzll: {
Value *ArgValue = EmitScalarExpr(E->getArg(0));
- const llvm::Type *ArgType = ArgValue->getType();
- Value *F = CGM.getIntrinsic(Intrinsic::cttz, &ArgType, 1);
+ llvm::Type *ArgType = ArgValue->getType();
+ Value *F = CGM.getIntrinsic(Intrinsic::cttz, ArgType);
const llvm::Type *ResultType = ConvertType(E->getType());
Value *Result = Builder.CreateCall(F, ArgValue, "tmp");
@@ -247,8 +248,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BI__builtin_clzll: {
Value *ArgValue = EmitScalarExpr(E->getArg(0));
- const llvm::Type *ArgType = ArgValue->getType();
- Value *F = CGM.getIntrinsic(Intrinsic::ctlz, &ArgType, 1);
+ llvm::Type *ArgType = ArgValue->getType();
+ Value *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType);
const llvm::Type *ResultType = ConvertType(E->getType());
Value *Result = Builder.CreateCall(F, ArgValue, "tmp");
@@ -263,8 +264,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
// ffs(x) -> x ? cttz(x) + 1 : 0
Value *ArgValue = EmitScalarExpr(E->getArg(0));
- const llvm::Type *ArgType = ArgValue->getType();
- Value *F = CGM.getIntrinsic(Intrinsic::cttz, &ArgType, 1);
+ llvm::Type *ArgType = ArgValue->getType();
+ Value *F = CGM.getIntrinsic(Intrinsic::cttz, ArgType);
const llvm::Type *ResultType = ConvertType(E->getType());
Value *Tmp = Builder.CreateAdd(Builder.CreateCall(F, ArgValue, "tmp"),
@@ -283,8 +284,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
// parity(x) -> ctpop(x) & 1
Value *ArgValue = EmitScalarExpr(E->getArg(0));
- const llvm::Type *ArgType = ArgValue->getType();
- Value *F = CGM.getIntrinsic(Intrinsic::ctpop, &ArgType, 1);
+ llvm::Type *ArgType = ArgValue->getType();
+ Value *F = CGM.getIntrinsic(Intrinsic::ctpop, ArgType);
const llvm::Type *ResultType = ConvertType(E->getType());
Value *Tmp = Builder.CreateCall(F, ArgValue, "tmp");
@@ -300,8 +301,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BI__builtin_popcountll: {
Value *ArgValue = EmitScalarExpr(E->getArg(0));
- const llvm::Type *ArgType = ArgValue->getType();
- Value *F = CGM.getIntrinsic(Intrinsic::ctpop, &ArgType, 1);
+ llvm::Type *ArgType = ArgValue->getType();
+ Value *F = CGM.getIntrinsic(Intrinsic::ctpop, ArgType);
const llvm::Type *ResultType = ConvertType(E->getType());
Value *Result = Builder.CreateCall(F, ArgValue, "tmp");
@@ -311,25 +312,27 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
return RValue::get(Result);
}
case Builtin::BI__builtin_expect: {
- // FIXME: pass expect through to LLVM
Value *ArgValue = EmitScalarExpr(E->getArg(0));
- if (E->getArg(1)->HasSideEffects(getContext()))
- (void)EmitScalarExpr(E->getArg(1));
- return RValue::get(ArgValue);
+ llvm::Type *ArgType = ArgValue->getType();
+
+ Value *FnExpect = CGM.getIntrinsic(Intrinsic::expect, ArgType);
+ Value *ExpectedValue = EmitScalarExpr(E->getArg(1));
+
+ Value *Result = Builder.CreateCall2(FnExpect, ArgValue, ExpectedValue,
+ "expval");
+ return RValue::get(Result);
}
case Builtin::BI__builtin_bswap32:
case Builtin::BI__builtin_bswap64: {
Value *ArgValue = EmitScalarExpr(E->getArg(0));
- const llvm::Type *ArgType = ArgValue->getType();
- Value *F = CGM.getIntrinsic(Intrinsic::bswap, &ArgType, 1);
+ llvm::Type *ArgType = ArgValue->getType();
+ Value *F = CGM.getIntrinsic(Intrinsic::bswap, ArgType);
return RValue::get(Builder.CreateCall(F, ArgValue, "tmp"));
}
case Builtin::BI__builtin_object_size: {
// We pass this builtin onto the optimizer so that it can
// figure out the object size in more complex cases.
- const llvm::Type *ResType[] = {
- ConvertType(E->getType())
- };
+ llvm::Type *ResType = ConvertType(E->getType());
// LLVM only supports 0 and 2, make sure that we pass along that
// as a boolean.
@@ -339,7 +342,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
uint64_t val = CI->getZExtValue();
CI = ConstantInt::get(Builder.getInt1Ty(), (val & 0x2) >> 1);
- Value *F = CGM.getIntrinsic(Intrinsic::objectsize, ResType, 1);
+ Value *F = CGM.getIntrinsic(Intrinsic::objectsize, ResType);
return RValue::get(Builder.CreateCall2(F,
EmitScalarExpr(E->getArg(0)),
CI));
@@ -351,11 +354,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
llvm::ConstantInt::get(Int32Ty, 0);
Locality = (E->getNumArgs() > 2) ? EmitScalarExpr(E->getArg(2)) :
llvm::ConstantInt::get(Int32Ty, 3);
- Value *F = CGM.getIntrinsic(Intrinsic::prefetch, 0, 0);
- return RValue::get(Builder.CreateCall3(F, Address, RW, Locality));
+ Value *Data = llvm::ConstantInt::get(Int32Ty, 1);
+ Value *F = CGM.getIntrinsic(Intrinsic::prefetch);
+ return RValue::get(Builder.CreateCall4(F, Address, RW, Locality, Data));
}
case Builtin::BI__builtin_trap: {
- Value *F = CGM.getIntrinsic(Intrinsic::trap, 0, 0);
+ Value *F = CGM.getIntrinsic(Intrinsic::trap);
return RValue::get(Builder.CreateCall(F));
}
case Builtin::BI__builtin_unreachable: {
@@ -375,8 +379,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BI__builtin_powil: {
Value *Base = EmitScalarExpr(E->getArg(0));
Value *Exponent = EmitScalarExpr(E->getArg(1));
- const llvm::Type *ArgType = Base->getType();
- Value *F = CGM.getIntrinsic(Intrinsic::powi, &ArgType, 1);
+ llvm::Type *ArgType = Base->getType();
+ Value *F = CGM.getIntrinsic(Intrinsic::powi, ArgType);
return RValue::get(Builder.CreateCall2(F, Base, Exponent, "tmp"));
}
@@ -630,20 +634,20 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
// this instead of hard-coding 0, which is correct for most targets.
int32_t Offset = 0;
- Value *F = CGM.getIntrinsic(Intrinsic::eh_dwarf_cfa, 0, 0);
+ Value *F = CGM.getIntrinsic(Intrinsic::eh_dwarf_cfa);
return RValue::get(Builder.CreateCall(F,
llvm::ConstantInt::get(Int32Ty, Offset)));
}
case Builtin::BI__builtin_return_address: {
Value *Depth = EmitScalarExpr(E->getArg(0));
Depth = Builder.CreateIntCast(Depth, Int32Ty, false, "tmp");
- Value *F = CGM.getIntrinsic(Intrinsic::returnaddress, 0, 0);
+ Value *F = CGM.getIntrinsic(Intrinsic::returnaddress);
return RValue::get(Builder.CreateCall(F, Depth));
}
case Builtin::BI__builtin_frame_address: {
Value *Depth = EmitScalarExpr(E->getArg(0));
Depth = Builder.CreateIntCast(Depth, Int32Ty, false, "tmp");
- Value *F = CGM.getIntrinsic(Intrinsic::frameaddress, 0, 0);
+ Value *F = CGM.getIntrinsic(Intrinsic::frameaddress);
return RValue::get(Builder.CreateCall(F, Depth));
}
case Builtin::BI__builtin_extract_return_addr: {
@@ -681,8 +685,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
"LLVM's __builtin_eh_return only supports 32- and 64-bit variants");
Value *F = CGM.getIntrinsic(IntTy->getBitWidth() == 32
? Intrinsic::eh_return_i32
- : Intrinsic::eh_return_i64,
- 0, 0);
+ : Intrinsic::eh_return_i64);
Builder.CreateCall2(F, Int, Ptr);
Builder.CreateUnreachable();
@@ -692,7 +695,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
return RValue::get(0);
}
case Builtin::BI__builtin_unwind_init: {
- Value *F = CGM.getIntrinsic(Intrinsic::eh_unwind_init, 0, 0);
+ Value *F = CGM.getIntrinsic(Intrinsic::eh_unwind_init);
return RValue::get(Builder.CreateCall(F));
}
case Builtin::BI__builtin_extend_pointer: {
@@ -860,13 +863,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
unsigned AddrSpace =
cast<llvm::PointerType>(DestPtr->getType())->getAddressSpace();
- const llvm::IntegerType *IntType =
+ llvm::IntegerType *IntType =
llvm::IntegerType::get(getLLVMContext(),
getContext().getTypeSize(T));
- const llvm::Type *IntPtrType = IntType->getPointerTo(AddrSpace);
- const llvm::Type *IntrinsicTypes[2] = { IntType, IntPtrType };
+ llvm::Type *IntPtrType = IntType->getPointerTo(AddrSpace);
+ llvm::Type *IntrinsicTypes[2] = { IntType, IntPtrType };
Value *AtomF = CGM.getIntrinsic(Intrinsic::atomic_cmp_swap,
- IntrinsicTypes, 2);
+ IntrinsicTypes);
Value *Args[3];
Args[0] = Builder.CreateBitCast(DestPtr, IntPtrType);
@@ -875,7 +878,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Args[1] = EmitToInt(*this, Args[1], T, IntType);
Args[2] = EmitToInt(*this, EmitScalarExpr(E->getArg(2)), T, IntType);
- Value *Result = EmitCallWithBarrier(*this, AtomF, Args, Args + 3);
+ Value *Result = EmitCallWithBarrier(*this, AtomF, Args);
Result = EmitFromInt(*this, Result, T, ValueType);
return RValue::get(Result);
}
@@ -890,13 +893,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
unsigned AddrSpace =
cast<llvm::PointerType>(DestPtr->getType())->getAddressSpace();
- const llvm::IntegerType *IntType =
+ llvm::IntegerType *IntType =
llvm::IntegerType::get(getLLVMContext(),
getContext().getTypeSize(T));
- const llvm::Type *IntPtrType = IntType->getPointerTo(AddrSpace);
- const llvm::Type *IntrinsicTypes[2] = { IntType, IntPtrType };
+ llvm::Type *IntPtrType = IntType->getPointerTo(AddrSpace);
+ llvm::Type *IntrinsicTypes[2] = { IntType, IntPtrType };
Value *AtomF = CGM.getIntrinsic(Intrinsic::atomic_cmp_swap,
- IntrinsicTypes, 2);
+ IntrinsicTypes);
Value *Args[3];
Args[0] = Builder.CreateBitCast(DestPtr, IntPtrType);
@@ -904,7 +907,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Args[2] = EmitToInt(*this, EmitScalarExpr(E->getArg(2)), T, IntType);
Value *OldVal = Args[1];
- Value *PrevVal = EmitCallWithBarrier(*this, AtomF, Args, Args + 3);
+ Value *PrevVal = EmitCallWithBarrier(*this, AtomF, Args);
Value *Result = Builder.CreateICmpEQ(PrevVal, OldVal);
// zext bool to int.
Result = Builder.CreateZExt(Result, ConvertType(E->getType()));
@@ -953,7 +956,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
EmitScalarExpr(E->getArg(3)),
EmitScalarExpr(E->getArg(4))
};
- Builder.CreateCall(CGM.getIntrinsic(Intrinsic::memory_barrier), C, C + 5);
+ Builder.CreateCall(CGM.getIntrinsic(Intrinsic::memory_barrier), C);
return RValue::get(0);
}
@@ -977,11 +980,27 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
break;
Value *Base = EmitScalarExpr(E->getArg(0));
Value *Exponent = EmitScalarExpr(E->getArg(1));
- const llvm::Type *ArgType = Base->getType();
- Value *F = CGM.getIntrinsic(Intrinsic::pow, &ArgType, 1);
+ llvm::Type *ArgType = Base->getType();
+ Value *F = CGM.getIntrinsic(Intrinsic::pow, ArgType);
return RValue::get(Builder.CreateCall2(F, Base, Exponent, "tmp"));
}
+ case Builtin::BIfma:
+ case Builtin::BIfmaf:
+ case Builtin::BIfmal:
+ case Builtin::BI__builtin_fma:
+ case Builtin::BI__builtin_fmaf:
+ case Builtin::BI__builtin_fmal: {
+ // Rewrite fma to intrinsic.
+ Value *FirstArg = EmitScalarExpr(E->getArg(0));
+ llvm::Type *ArgType = FirstArg->getType();
+ Value *F = CGM.getIntrinsic(Intrinsic::fma, ArgType);
+ return RValue::get(Builder.CreateCall3(F, FirstArg,
+ EmitScalarExpr(E->getArg(1)),
+ EmitScalarExpr(E->getArg(2)),
+ "tmp"));
+ }
+
case Builtin::BI__builtin_signbit:
case Builtin::BI__builtin_signbitf:
case Builtin::BI__builtin_signbitl: {
@@ -1055,7 +1074,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Args.push_back(ArgValue);
}
- Value *V = Builder.CreateCall(F, Args.data(), Args.data() + Args.size());
+ Value *V = Builder.CreateCall(F, Args);
QualType BuiltinRetType = E->getType();
const llvm::Type *RetTy = llvm::Type::getVoidTy(getLLVMContext());
@@ -1099,8 +1118,7 @@ Value *CodeGenFunction::EmitTargetBuiltinExpr(unsigned BuiltinID,
}
}
-static const llvm::VectorType *GetNeonType(LLVMContext &C, unsigned type,
- bool q) {
+static llvm::VectorType *GetNeonType(LLVMContext &C, unsigned type, bool q) {
switch (type) {
default: break;
case 0:
@@ -1133,7 +1151,7 @@ Value *CodeGenFunction::EmitNeonCall(Function *F, SmallVectorImpl<Value*> &Ops,
else
Ops[j] = Builder.CreateBitCast(Ops[j], ai->getType(), name);
- return Builder.CreateCall(F, Ops.begin(), Ops.end(), name);
+ return Builder.CreateCall(F, Ops, name);
}
Value *CodeGenFunction::EmitNeonShiftVector(Value *V, const llvm::Type *Ty,
@@ -1181,8 +1199,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
const llvm::Type *Ty = CGM.getTypes().ConvertType(FD->getType());
const llvm::FunctionType *FTy = cast<llvm::FunctionType>(Ty);
llvm::StringRef Name = FD->getName();
- return Builder.CreateCall(CGM.CreateRuntimeFunction(FTy, Name),
- Ops.begin(), Ops.end());
+ return Builder.CreateCall(CGM.CreateRuntimeFunction(FTy, Name), Ops);
}
if (BuiltinID == ARM::BI__builtin_arm_ldrexd) {
@@ -1203,8 +1220,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
if (BuiltinID == ARM::BI__builtin_arm_strexd) {
Function *F = CGM.getIntrinsic(Intrinsic::arm_strexd);
- llvm::Type *STy = llvm::StructType::get(getLLVMContext(), Int32Ty, Int32Ty,
- NULL);
+ llvm::Type *STy = llvm::StructType::get(Int32Ty, Int32Ty, NULL);
Value *One = llvm::ConstantInt::get(Int32Ty, 1);
Value *Tmp = Builder.CreateAlloca(Int64Ty, One, "tmp");
@@ -1232,7 +1248,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
if (BuiltinID == ARM::BI__builtin_arm_vcvtr_f ||
BuiltinID == ARM::BI__builtin_arm_vcvtr_d) {
// Determine the overloaded type of this builtin.
- const llvm::Type *Ty;
+ llvm::Type *Ty;
if (BuiltinID == ARM::BI__builtin_arm_vcvtr_f)
Ty = llvm::Type::getFloatTy(getLLVMContext());
else
@@ -1243,8 +1259,8 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
unsigned Int = usgn ? Intrinsic::arm_vcvtru : Intrinsic::arm_vcvtr;
// Call the appropriate intrinsic.
- Function *F = CGM.getIntrinsic(Int, &Ty, 1);
- return Builder.CreateCall(F, Ops.begin(), Ops.end(), "vcvtr");
+ Function *F = CGM.getIntrinsic(Int, Ty);
+ return Builder.CreateCall(F, Ops, "vcvtr");
}
// Determine the type of this overloaded NEON intrinsic.
@@ -1255,8 +1271,8 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
(void)poly; // Only used in assert()s.
bool rightShift = false;
- const llvm::VectorType *VTy = GetNeonType(getLLVMContext(), type & 0x7, quad);
- const llvm::Type *Ty = VTy;
+ llvm::VectorType *VTy = GetNeonType(getLLVMContext(), type & 0x7, quad);
+ llvm::Type *Ty = VTy;
if (!Ty)
return 0;
@@ -1266,13 +1282,13 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
case ARM::BI__builtin_neon_vabd_v:
case ARM::BI__builtin_neon_vabdq_v:
Int = usgn ? Intrinsic::arm_neon_vabdu : Intrinsic::arm_neon_vabds;
- return EmitNeonCall(CGM.getIntrinsic(Int, &Ty, 1), Ops, "vabd");
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vabd");
case ARM::BI__builtin_neon_vabs_v:
case ARM::BI__builtin_neon_vabsq_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vabs, &Ty, 1),
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vabs, Ty),
Ops, "vabs");
case ARM::BI__builtin_neon_vaddhn_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vaddhn, &Ty, 1),
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vaddhn, Ty),
Ops, "vaddhn");
case ARM::BI__builtin_neon_vcale_v:
std::swap(Ops[0], Ops[1]);
@@ -1300,17 +1316,17 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
}
case ARM::BI__builtin_neon_vcls_v:
case ARM::BI__builtin_neon_vclsq_v: {
- Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vcls, &Ty, 1);
+ Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vcls, Ty);
return EmitNeonCall(F, Ops, "vcls");
}
case ARM::BI__builtin_neon_vclz_v:
case ARM::BI__builtin_neon_vclzq_v: {
- Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vclz, &Ty, 1);
+ Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vclz, Ty);
return EmitNeonCall(F, Ops, "vclz");
}
case ARM::BI__builtin_neon_vcnt_v:
case ARM::BI__builtin_neon_vcntq_v: {
- Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vcnt, &Ty, 1);
+ Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vcnt, Ty);
return EmitNeonCall(F, Ops, "vcnt");
}
case ARM::BI__builtin_neon_vcvt_f16_v: {
@@ -1340,18 +1356,18 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
}
case ARM::BI__builtin_neon_vcvt_n_f32_v:
case ARM::BI__builtin_neon_vcvtq_n_f32_v: {
- const llvm::Type *Tys[2] = { GetNeonType(getLLVMContext(), 4, quad), Ty };
+ llvm::Type *Tys[2] = { GetNeonType(getLLVMContext(), 4, quad), Ty };
Int = usgn ? Intrinsic::arm_neon_vcvtfxu2fp : Intrinsic::arm_neon_vcvtfxs2fp;
- Function *F = CGM.getIntrinsic(Int, Tys, 2);
+ Function *F = CGM.getIntrinsic(Int, Tys);
return EmitNeonCall(F, Ops, "vcvt_n");
}
case ARM::BI__builtin_neon_vcvt_n_s32_v:
case ARM::BI__builtin_neon_vcvt_n_u32_v:
case ARM::BI__builtin_neon_vcvtq_n_s32_v:
case ARM::BI__builtin_neon_vcvtq_n_u32_v: {
- const llvm::Type *Tys[2] = { Ty, GetNeonType(getLLVMContext(), 4, quad) };
+ llvm::Type *Tys[2] = { Ty, GetNeonType(getLLVMContext(), 4, quad) };
Int = usgn ? Intrinsic::arm_neon_vcvtfp2fxu : Intrinsic::arm_neon_vcvtfp2fxs;
- Function *F = CGM.getIntrinsic(Int, Tys, 2);
+ Function *F = CGM.getIntrinsic(Int, Tys);
return EmitNeonCall(F, Ops, "vcvt_n");
}
case ARM::BI__builtin_neon_vext_v:
@@ -1381,15 +1397,15 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
case ARM::BI__builtin_neon_vhadd_v:
case ARM::BI__builtin_neon_vhaddq_v:
Int = usgn ? Intrinsic::arm_neon_vhaddu : Intrinsic::arm_neon_vhadds;
- return EmitNeonCall(CGM.getIntrinsic(Int, &Ty, 1), Ops, "vhadd");
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vhadd");
case ARM::BI__builtin_neon_vhsub_v:
case ARM::BI__builtin_neon_vhsubq_v:
Int = usgn ? Intrinsic::arm_neon_vhsubu : Intrinsic::arm_neon_vhsubs;
- return EmitNeonCall(CGM.getIntrinsic(Int, &Ty, 1), Ops, "vhsub");
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vhsub");
case ARM::BI__builtin_neon_vld1_v:
case ARM::BI__builtin_neon_vld1q_v:
Ops.push_back(GetPointeeAlignment(*this, E->getArg(0)));
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vld1, &Ty, 1),
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vld1, Ty),
Ops, "vld1");
case ARM::BI__builtin_neon_vld1_lane_v:
case ARM::BI__builtin_neon_vld1q_lane_v:
@@ -1410,7 +1426,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
}
case ARM::BI__builtin_neon_vld2_v:
case ARM::BI__builtin_neon_vld2q_v: {
- Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vld2, &Ty, 1);
+ Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vld2, Ty);
Value *Align = GetPointeeAlignment(*this, E->getArg(1));
Ops[1] = Builder.CreateCall2(F, Ops[1], Align, "vld2");
Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
@@ -1419,7 +1435,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
}
case ARM::BI__builtin_neon_vld3_v:
case ARM::BI__builtin_neon_vld3q_v: {
- Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vld3, &Ty, 1);
+ Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vld3, Ty);
Value *Align = GetPointeeAlignment(*this, E->getArg(1));
Ops[1] = Builder.CreateCall2(F, Ops[1], Align, "vld3");
Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
@@ -1428,7 +1444,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
}
case ARM::BI__builtin_neon_vld4_v:
case ARM::BI__builtin_neon_vld4q_v: {
- Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vld4, &Ty, 1);
+ Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vld4, Ty);
Value *Align = GetPointeeAlignment(*this, E->getArg(1));
Ops[1] = Builder.CreateCall2(F, Ops[1], Align, "vld4");
Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
@@ -1437,36 +1453,42 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
}
case ARM::BI__builtin_neon_vld2_lane_v:
case ARM::BI__builtin_neon_vld2q_lane_v: {
- Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vld2lane, &Ty, 1);
+ Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vld2lane, Ty);
Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
Ops[3] = Builder.CreateBitCast(Ops[3], Ty);
Ops.push_back(GetPointeeAlignment(*this, E->getArg(1)));
- Ops[1] = Builder.CreateCall(F, Ops.begin() + 1, Ops.end(), "vld2_lane");
+ Ops[1] = Builder.CreateCall(F,
+ ArrayRef<Value *>(Ops.begin() + 1, Ops.end()),
+ "vld2_lane");
Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
return Builder.CreateStore(Ops[1], Ops[0]);
}
case ARM::BI__builtin_neon_vld3_lane_v:
case ARM::BI__builtin_neon_vld3q_lane_v: {
- Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vld3lane, &Ty, 1);
+ Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vld3lane, Ty);
Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
Ops[3] = Builder.CreateBitCast(Ops[3], Ty);
Ops[4] = Builder.CreateBitCast(Ops[4], Ty);
Ops.push_back(GetPointeeAlignment(*this, E->getArg(1)));
- Ops[1] = Builder.CreateCall(F, Ops.begin() + 1, Ops.end(), "vld3_lane");
+ Ops[1] = Builder.CreateCall(F,
+ ArrayRef<Value *>(Ops.begin() + 1, Ops.end()),
+ "vld3_lane");
Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
return Builder.CreateStore(Ops[1], Ops[0]);
}
case ARM::BI__builtin_neon_vld4_lane_v:
case ARM::BI__builtin_neon_vld4q_lane_v: {
- Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vld4lane, &Ty, 1);
+ Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vld4lane, Ty);
Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
Ops[3] = Builder.CreateBitCast(Ops[3], Ty);
Ops[4] = Builder.CreateBitCast(Ops[4], Ty);
Ops[5] = Builder.CreateBitCast(Ops[5], Ty);
Ops.push_back(GetPointeeAlignment(*this, E->getArg(1)));
- Ops[1] = Builder.CreateCall(F, Ops.begin() + 1, Ops.end(), "vld3_lane");
+ Ops[1] = Builder.CreateCall(F,
+ ArrayRef<Value *>(Ops.begin() + 1, Ops.end()),
+ "vld3_lane");
Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
return Builder.CreateStore(Ops[1], Ops[0]);
@@ -1488,7 +1510,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
break;
default: assert(0 && "unknown vld_dup intrinsic?");
}
- Function *F = CGM.getIntrinsic(Int, &Ty, 1);
+ Function *F = CGM.getIntrinsic(Int, Ty);
Value *Align = GetPointeeAlignment(*this, E->getArg(1));
Ops[1] = Builder.CreateCall2(F, Ops[1], Align, "vld_dup");
Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
@@ -1507,7 +1529,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
break;
default: assert(0 && "unknown vld_dup intrinsic?");
}
- Function *F = CGM.getIntrinsic(Int, &Ty, 1);
+ Function *F = CGM.getIntrinsic(Int, Ty);
const llvm::StructType *STy = cast<llvm::StructType>(F->getReturnType());
SmallVector<Value*, 6> Args;
@@ -1518,7 +1540,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Args.push_back(CI);
Args.push_back(GetPointeeAlignment(*this, E->getArg(1)));
- Ops[1] = Builder.CreateCall(F, Args.begin(), Args.end(), "vld_dup");
+ Ops[1] = Builder.CreateCall(F, Args, "vld_dup");
// splat lane 0 to all elts in each vector of the result.
for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
Value *Val = Builder.CreateExtractValue(Ops[1], i);
@@ -1534,11 +1556,11 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
case ARM::BI__builtin_neon_vmax_v:
case ARM::BI__builtin_neon_vmaxq_v:
Int = usgn ? Intrinsic::arm_neon_vmaxu : Intrinsic::arm_neon_vmaxs;
- return EmitNeonCall(CGM.getIntrinsic(Int, &Ty, 1), Ops, "vmax");
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vmax");
case ARM::BI__builtin_neon_vmin_v:
case ARM::BI__builtin_neon_vminq_v:
Int = usgn ? Intrinsic::arm_neon_vminu : Intrinsic::arm_neon_vmins;
- return EmitNeonCall(CGM.getIntrinsic(Int, &Ty, 1), Ops, "vmin");
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vmin");
case ARM::BI__builtin_neon_vmovl_v: {
const llvm::Type *DTy =llvm::VectorType::getTruncatedElementVectorType(VTy);
Ops[0] = Builder.CreateBitCast(Ops[0], DTy);
@@ -1554,12 +1576,12 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
case ARM::BI__builtin_neon_vmul_v:
case ARM::BI__builtin_neon_vmulq_v:
assert(poly && "vmul builtin only supported for polynomial types");
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vmulp, &Ty, 1),
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vmulp, Ty),
Ops, "vmul");
case ARM::BI__builtin_neon_vmull_v:
Int = usgn ? Intrinsic::arm_neon_vmullu : Intrinsic::arm_neon_vmulls;
Int = poly ? (unsigned)Intrinsic::arm_neon_vmullp : Int;
- return EmitNeonCall(CGM.getIntrinsic(Int, &Ty, 1), Ops, "vmull");
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vmull");
case ARM::BI__builtin_neon_vpadal_v:
case ARM::BI__builtin_neon_vpadalq_v: {
Int = usgn ? Intrinsic::arm_neon_vpadalu : Intrinsic::arm_neon_vpadals;
@@ -1567,13 +1589,13 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
unsigned EltBits = VTy->getElementType()->getPrimitiveSizeInBits();
const llvm::Type *EltTy =
llvm::IntegerType::get(getLLVMContext(), EltBits / 2);
- const llvm::Type *NarrowTy =
+ llvm::Type *NarrowTy =
llvm::VectorType::get(EltTy, VTy->getNumElements() * 2);
- const llvm::Type *Tys[2] = { Ty, NarrowTy };
- return EmitNeonCall(CGM.getIntrinsic(Int, Tys, 2), Ops, "vpadal");
+ llvm::Type *Tys[2] = { Ty, NarrowTy };
+ return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vpadal");
}
case ARM::BI__builtin_neon_vpadd_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vpadd, &Ty, 1),
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vpadd, Ty),
Ops, "vpadd");
case ARM::BI__builtin_neon_vpaddl_v:
case ARM::BI__builtin_neon_vpaddlq_v: {
@@ -1581,120 +1603,120 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
// The source operand type has twice as many elements of half the size.
unsigned EltBits = VTy->getElementType()->getPrimitiveSizeInBits();
const llvm::Type *EltTy = llvm::IntegerType::get(getLLVMContext(), EltBits / 2);
- const llvm::Type *NarrowTy =
+ llvm::Type *NarrowTy =
llvm::VectorType::get(EltTy, VTy->getNumElements() * 2);
- const llvm::Type *Tys[2] = { Ty, NarrowTy };
- return EmitNeonCall(CGM.getIntrinsic(Int, Tys, 2), Ops, "vpaddl");
+ llvm::Type *Tys[2] = { Ty, NarrowTy };
+ return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vpaddl");
}
case ARM::BI__builtin_neon_vpmax_v:
Int = usgn ? Intrinsic::arm_neon_vpmaxu : Intrinsic::arm_neon_vpmaxs;
- return EmitNeonCall(CGM.getIntrinsic(Int, &Ty, 1), Ops, "vpmax");
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vpmax");
case ARM::BI__builtin_neon_vpmin_v:
Int = usgn ? Intrinsic::arm_neon_vpminu : Intrinsic::arm_neon_vpmins;
- return EmitNeonCall(CGM.getIntrinsic(Int, &Ty, 1), Ops, "vpmin");
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vpmin");
case ARM::BI__builtin_neon_vqabs_v:
case ARM::BI__builtin_neon_vqabsq_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vqabs, &Ty, 1),
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vqabs, Ty),
Ops, "vqabs");
case ARM::BI__builtin_neon_vqadd_v:
case ARM::BI__builtin_neon_vqaddq_v:
Int = usgn ? Intrinsic::arm_neon_vqaddu : Intrinsic::arm_neon_vqadds;
- return EmitNeonCall(CGM.getIntrinsic(Int, &Ty, 1), Ops, "vqadd");
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqadd");
case ARM::BI__builtin_neon_vqdmlal_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vqdmlal, &Ty, 1),
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vqdmlal, Ty),
Ops, "vqdmlal");
case ARM::BI__builtin_neon_vqdmlsl_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vqdmlsl, &Ty, 1),
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vqdmlsl, Ty),
Ops, "vqdmlsl");
case ARM::BI__builtin_neon_vqdmulh_v:
case ARM::BI__builtin_neon_vqdmulhq_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vqdmulh, &Ty, 1),
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vqdmulh, Ty),
Ops, "vqdmulh");
case ARM::BI__builtin_neon_vqdmull_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vqdmull, &Ty, 1),
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vqdmull, Ty),
Ops, "vqdmull");
case ARM::BI__builtin_neon_vqmovn_v:
Int = usgn ? Intrinsic::arm_neon_vqmovnu : Intrinsic::arm_neon_vqmovns;
- return EmitNeonCall(CGM.getIntrinsic(Int, &Ty, 1), Ops, "vqmovn");
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqmovn");
case ARM::BI__builtin_neon_vqmovun_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vqmovnsu, &Ty, 1),
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vqmovnsu, Ty),
Ops, "vqdmull");
case ARM::BI__builtin_neon_vqneg_v:
case ARM::BI__builtin_neon_vqnegq_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vqneg, &Ty, 1),
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vqneg, Ty),
Ops, "vqneg");
case ARM::BI__builtin_neon_vqrdmulh_v:
case ARM::BI__builtin_neon_vqrdmulhq_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vqrdmulh, &Ty, 1),
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vqrdmulh, Ty),
Ops, "vqrdmulh");
case ARM::BI__builtin_neon_vqrshl_v:
case ARM::BI__builtin_neon_vqrshlq_v:
Int = usgn ? Intrinsic::arm_neon_vqrshiftu : Intrinsic::arm_neon_vqrshifts;
- return EmitNeonCall(CGM.getIntrinsic(Int, &Ty, 1), Ops, "vqrshl");
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqrshl");
case ARM::BI__builtin_neon_vqrshrn_n_v:
Int = usgn ? Intrinsic::arm_neon_vqrshiftnu : Intrinsic::arm_neon_vqrshiftns;
- return EmitNeonCall(CGM.getIntrinsic(Int, &Ty, 1), Ops, "vqrshrn_n",
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqrshrn_n",
1, true);
case ARM::BI__builtin_neon_vqrshrun_n_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vqrshiftnsu, &Ty, 1),
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vqrshiftnsu, Ty),
Ops, "vqrshrun_n", 1, true);
case ARM::BI__builtin_neon_vqshl_v:
case ARM::BI__builtin_neon_vqshlq_v:
Int = usgn ? Intrinsic::arm_neon_vqshiftu : Intrinsic::arm_neon_vqshifts;
- return EmitNeonCall(CGM.getIntrinsic(Int, &Ty, 1), Ops, "vqshl");
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqshl");
case ARM::BI__builtin_neon_vqshl_n_v:
case ARM::BI__builtin_neon_vqshlq_n_v:
Int = usgn ? Intrinsic::arm_neon_vqshiftu : Intrinsic::arm_neon_vqshifts;
- return EmitNeonCall(CGM.getIntrinsic(Int, &Ty, 1), Ops, "vqshl_n",
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqshl_n",
1, false);
case ARM::BI__builtin_neon_vqshlu_n_v:
case ARM::BI__builtin_neon_vqshluq_n_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vqshiftsu, &Ty, 1),
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vqshiftsu, Ty),
Ops, "vqshlu", 1, false);
case ARM::BI__builtin_neon_vqshrn_n_v:
Int = usgn ? Intrinsic::arm_neon_vqshiftnu : Intrinsic::arm_neon_vqshiftns;
- return EmitNeonCall(CGM.getIntrinsic(Int, &Ty, 1), Ops, "vqshrn_n",
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqshrn_n",
1, true);
case ARM::BI__builtin_neon_vqshrun_n_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vqshiftnsu, &Ty, 1),
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vqshiftnsu, Ty),
Ops, "vqshrun_n", 1, true);
case ARM::BI__builtin_neon_vqsub_v:
case ARM::BI__builtin_neon_vqsubq_v:
Int = usgn ? Intrinsic::arm_neon_vqsubu : Intrinsic::arm_neon_vqsubs;
- return EmitNeonCall(CGM.getIntrinsic(Int, &Ty, 1), Ops, "vqsub");
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqsub");
case ARM::BI__builtin_neon_vraddhn_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vraddhn, &Ty, 1),
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vraddhn, Ty),
Ops, "vraddhn");
case ARM::BI__builtin_neon_vrecpe_v:
case ARM::BI__builtin_neon_vrecpeq_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vrecpe, &Ty, 1),
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vrecpe, Ty),
Ops, "vrecpe");
case ARM::BI__builtin_neon_vrecps_v:
case ARM::BI__builtin_neon_vrecpsq_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vrecps, &Ty, 1),
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vrecps, Ty),
Ops, "vrecps");
case ARM::BI__builtin_neon_vrhadd_v:
case ARM::BI__builtin_neon_vrhaddq_v:
Int = usgn ? Intrinsic::arm_neon_vrhaddu : Intrinsic::arm_neon_vrhadds;
- return EmitNeonCall(CGM.getIntrinsic(Int, &Ty, 1), Ops, "vrhadd");
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrhadd");
case ARM::BI__builtin_neon_vrshl_v:
case ARM::BI__builtin_neon_vrshlq_v:
Int = usgn ? Intrinsic::arm_neon_vrshiftu : Intrinsic::arm_neon_vrshifts;
- return EmitNeonCall(CGM.getIntrinsic(Int, &Ty, 1), Ops, "vrshl");
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrshl");
case ARM::BI__builtin_neon_vrshrn_n_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vrshiftn, &Ty, 1),
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vrshiftn, Ty),
Ops, "vrshrn_n", 1, true);
case ARM::BI__builtin_neon_vrshr_n_v:
case ARM::BI__builtin_neon_vrshrq_n_v:
Int = usgn ? Intrinsic::arm_neon_vrshiftu : Intrinsic::arm_neon_vrshifts;
- return EmitNeonCall(CGM.getIntrinsic(Int, &Ty, 1), Ops, "vrshr_n", 1, true);
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrshr_n", 1, true);
case ARM::BI__builtin_neon_vrsqrte_v:
case ARM::BI__builtin_neon_vrsqrteq_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vrsqrte, &Ty, 1),
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vrsqrte, Ty),
Ops, "vrsqrte");
case ARM::BI__builtin_neon_vrsqrts_v:
case ARM::BI__builtin_neon_vrsqrtsq_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vrsqrts, &Ty, 1),
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vrsqrts, Ty),
Ops, "vrsqrts");
case ARM::BI__builtin_neon_vrsra_n_v:
case ARM::BI__builtin_neon_vrsraq_n_v:
@@ -1702,10 +1724,10 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
Ops[2] = EmitNeonShiftVector(Ops[2], Ty, true);
Int = usgn ? Intrinsic::arm_neon_vrshiftu : Intrinsic::arm_neon_vrshifts;
- Ops[1] = Builder.CreateCall2(CGM.getIntrinsic(Int, &Ty, 1), Ops[1], Ops[2]);
+ Ops[1] = Builder.CreateCall2(CGM.getIntrinsic(Int, Ty), Ops[1], Ops[2]);
return Builder.CreateAdd(Ops[0], Ops[1], "vrsra_n");
case ARM::BI__builtin_neon_vrsubhn_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vrsubhn, &Ty, 1),
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vrsubhn, Ty),
Ops, "vrsubhn");
case ARM::BI__builtin_neon_vset_lane_i8:
case ARM::BI__builtin_neon_vset_lane_i16:
@@ -1722,16 +1744,16 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
case ARM::BI__builtin_neon_vshl_v:
case ARM::BI__builtin_neon_vshlq_v:
Int = usgn ? Intrinsic::arm_neon_vshiftu : Intrinsic::arm_neon_vshifts;
- return EmitNeonCall(CGM.getIntrinsic(Int, &Ty, 1), Ops, "vshl");
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vshl");
case ARM::BI__builtin_neon_vshll_n_v:
Int = usgn ? Intrinsic::arm_neon_vshiftlu : Intrinsic::arm_neon_vshiftls;
- return EmitNeonCall(CGM.getIntrinsic(Int, &Ty, 1), Ops, "vshll", 1);
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vshll", 1);
case ARM::BI__builtin_neon_vshl_n_v:
case ARM::BI__builtin_neon_vshlq_n_v:
Ops[1] = EmitNeonShiftVector(Ops[1], Ty, false);
return Builder.CreateShl(Builder.CreateBitCast(Ops[0],Ty), Ops[1], "vshl_n");
case ARM::BI__builtin_neon_vshrn_n_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vshiftn, &Ty, 1),
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vshiftn, Ty),
Ops, "vshrn_n", 1, true);
case ARM::BI__builtin_neon_vshr_n_v:
case ARM::BI__builtin_neon_vshrq_n_v:
@@ -1747,7 +1769,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
case ARM::BI__builtin_neon_vsli_n_v:
case ARM::BI__builtin_neon_vsliq_n_v:
Ops[2] = EmitNeonShiftVector(Ops[2], Ty, rightShift);
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vshiftins, &Ty, 1),
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vshiftins, Ty),
Ops, "vsli_n");
case ARM::BI__builtin_neon_vsra_n_v:
case ARM::BI__builtin_neon_vsraq_n_v:
@@ -1762,7 +1784,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
case ARM::BI__builtin_neon_vst1_v:
case ARM::BI__builtin_neon_vst1q_v:
Ops.push_back(GetPointeeAlignment(*this, E->getArg(0)));
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst1, &Ty, 1),
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst1, Ty),
Ops, "");
case ARM::BI__builtin_neon_vst1_lane_v:
case ARM::BI__builtin_neon_vst1q_lane_v:
@@ -1773,35 +1795,35 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
case ARM::BI__builtin_neon_vst2_v:
case ARM::BI__builtin_neon_vst2q_v:
Ops.push_back(GetPointeeAlignment(*this, E->getArg(0)));
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst2, &Ty, 1),
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst2, Ty),
Ops, "");
case ARM::BI__builtin_neon_vst2_lane_v:
case ARM::BI__builtin_neon_vst2q_lane_v:
Ops.push_back(GetPointeeAlignment(*this, E->getArg(0)));
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst2lane, &Ty, 1),
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst2lane, Ty),
Ops, "");
case ARM::BI__builtin_neon_vst3_v:
case ARM::BI__builtin_neon_vst3q_v:
Ops.push_back(GetPointeeAlignment(*this, E->getArg(0)));
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst3, &Ty, 1),
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst3, Ty),
Ops, "");
case ARM::BI__builtin_neon_vst3_lane_v:
case ARM::BI__builtin_neon_vst3q_lane_v:
Ops.push_back(GetPointeeAlignment(*this, E->getArg(0)));
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst3lane, &Ty, 1),
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst3lane, Ty),
Ops, "");
case ARM::BI__builtin_neon_vst4_v:
case ARM::BI__builtin_neon_vst4q_v:
Ops.push_back(GetPointeeAlignment(*this, E->getArg(0)));
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst4, &Ty, 1),
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst4, Ty),
Ops, "");
case ARM::BI__builtin_neon_vst4_lane_v:
case ARM::BI__builtin_neon_vst4q_lane_v:
Ops.push_back(GetPointeeAlignment(*this, E->getArg(0)));
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst4lane, &Ty, 1),
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst4lane, Ty),
Ops, "");
case ARM::BI__builtin_neon_vsubhn_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vsubhn, &Ty, 1),
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vsubhn, Ty),
Ops, "vsubhn");
case ARM::BI__builtin_neon_vtbl1_v:
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vtbl1),
@@ -2005,7 +2027,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
break;
}
llvm::Function *F = CGM.getIntrinsic(ID);
- return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), name);
+ return Builder.CreateCall(F, Ops, name);
}
case X86::BI__builtin_ia32_vec_init_v8qi:
case X86::BI__builtin_ia32_vec_init_v4hi:
@@ -2065,15 +2087,15 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
break;
}
llvm::Function *F = CGM.getIntrinsic(ID);
- return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), name);
+ return Builder.CreateCall(F, Ops, name);
}
case X86::BI__builtin_ia32_cmpps: {
llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_sse_cmp_ps);
- return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), "cmpps");
+ return Builder.CreateCall(F, Ops, "cmpps");
}
case X86::BI__builtin_ia32_cmpss: {
llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_sse_cmp_ss);
- return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), "cmpss");
+ return Builder.CreateCall(F, Ops, "cmpss");
}
case X86::BI__builtin_ia32_ldmxcsr: {
const llvm::Type *PtrTy = Int8PtrTy;
@@ -2093,11 +2115,11 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
}
case X86::BI__builtin_ia32_cmppd: {
llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_sse2_cmp_pd);
- return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), "cmppd");
+ return Builder.CreateCall(F, Ops, "cmppd");
}
case X86::BI__builtin_ia32_cmpsd: {
llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_sse2_cmp_sd);
- return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), "cmpsd");
+ return Builder.CreateCall(F, Ops, "cmpsd");
}
case X86::BI__builtin_ia32_storehps:
case X86::BI__builtin_ia32_storelps: {
@@ -2141,7 +2163,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
// create i32 constant
llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_mmx_psrl_q);
- return Builder.CreateCall(F, &Ops[0], &Ops[0] + 2, "palignr");
+ return Builder.CreateCall(F, ArrayRef<Value *>(&Ops[0], 2), "palignr");
}
// If palignr is shifting the pair of vectors more than 32 bytes, emit zero.
@@ -2171,7 +2193,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
// create i32 constant
llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_sse2_psrl_dq);
- return Builder.CreateCall(F, &Ops[0], &Ops[0] + 2, "palignr");
+ return Builder.CreateCall(F, ArrayRef<Value *>(&Ops[0], 2), "palignr");
}
// If palignr is shifting the pair of vectors more than 32 bytes, emit zero.
@@ -2323,7 +2345,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
break;
}
llvm::Function *F = CGM.getIntrinsic(ID);
- return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), name);
+ return Builder.CreateCall(F, Ops, name);
}
}
}
@@ -2379,7 +2401,7 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
break;
}
llvm::Function *F = CGM.getIntrinsic(ID);
- return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), "");
+ return Builder.CreateCall(F, Ops, "");
}
// vec_st
@@ -2412,7 +2434,7 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
break;
}
llvm::Function *F = CGM.getIntrinsic(ID);
- return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), "");
+ return Builder.CreateCall(F, Ops, "");
}
}
return 0;
diff --git a/lib/CodeGen/CGCXXABI.cpp b/lib/CodeGen/CGCXXABI.cpp
index 92f1c63a3829..dcc28b45cfc3 100644
--- a/lib/CodeGen/CGCXXABI.cpp
+++ b/lib/CodeGen/CGCXXABI.cpp
@@ -34,7 +34,7 @@ static llvm::Constant *GetBogusMemberPointer(CodeGenModule &CGM,
return llvm::Constant::getNullValue(CGM.getTypes().ConvertType(T));
}
-const llvm::Type *
+llvm::Type *
CGCXXABI::ConvertMemberPointerType(const MemberPointerType *MPT) {
return CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType());
}
diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h
index de4df3dcbe84..29f299a43e37 100644
--- a/lib/CodeGen/CGCXXABI.h
+++ b/lib/CodeGen/CGCXXABI.h
@@ -82,7 +82,7 @@ public:
/// Find the LLVM type used to represent the given member pointer
/// type.
- virtual const llvm::Type *
+ virtual llvm::Type *
ConvertMemberPointerType(const MemberPointerType *MPT);
/// Load a member function from an object and a member function
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index 712ae89a4888..f8783ad08d00 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -1,4 +1,4 @@
-//===----- CGCall.h - Encapsulate calling convention details ----*- C++ -*-===//
+//===--- CGCall.cpp - Encapsulate calling convention details ----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -25,6 +25,8 @@
#include "llvm/Attributes.h"
#include "llvm/Support/CallSite.h"
#include "llvm/Target/TargetData.h"
+#include "llvm/InlineAsm.h"
+#include "llvm/Transforms/Utils/Local.h"
using namespace clang;
using namespace CodeGen;
@@ -65,31 +67,28 @@ static CanQualType GetReturnType(QualType RetTy) {
}
const CGFunctionInfo &
-CodeGenTypes::getFunctionInfo(CanQual<FunctionNoProtoType> FTNP,
- bool IsRecursive) {
+CodeGenTypes::getFunctionInfo(CanQual<FunctionNoProtoType> FTNP) {
return getFunctionInfo(FTNP->getResultType().getUnqualifiedType(),
llvm::SmallVector<CanQualType, 16>(),
- FTNP->getExtInfo(), IsRecursive);
+ FTNP->getExtInfo());
}
/// \param Args - contains any initial parameters besides those
/// in the formal type
static const CGFunctionInfo &getFunctionInfo(CodeGenTypes &CGT,
llvm::SmallVectorImpl<CanQualType> &ArgTys,
- CanQual<FunctionProtoType> FTP,
- bool IsRecursive = false) {
+ CanQual<FunctionProtoType> FTP) {
// FIXME: Kill copy.
for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i)
ArgTys.push_back(FTP->getArgType(i));
CanQualType ResTy = FTP->getResultType().getUnqualifiedType();
- return CGT.getFunctionInfo(ResTy, ArgTys, FTP->getExtInfo(), IsRecursive);
+ return CGT.getFunctionInfo(ResTy, ArgTys, FTP->getExtInfo());
}
const CGFunctionInfo &
-CodeGenTypes::getFunctionInfo(CanQual<FunctionProtoType> FTP,
- bool IsRecursive) {
+CodeGenTypes::getFunctionInfo(CanQual<FunctionProtoType> FTP) {
llvm::SmallVector<CanQualType, 16> ArgTys;
- return ::getFunctionInfo(*this, ArgTys, FTP, IsRecursive);
+ return ::getFunctionInfo(*this, ArgTys, FTP);
}
static CallingConv getCallingConventionForDecl(const Decl *D) {
@@ -189,13 +188,15 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const ObjCMethodDecl *MD) {
e = MD->param_end(); i != e; ++i) {
ArgTys.push_back(Context.getCanonicalParamType((*i)->getType()));
}
- return getFunctionInfo(GetReturnType(MD->getResultType()),
- ArgTys,
- FunctionType::ExtInfo(
- /*NoReturn*/ false,
- /*HasRegParm*/ false,
- /*RegParm*/ 0,
- getCallingConventionForDecl(MD)));
+
+ FunctionType::ExtInfo einfo;
+ einfo = einfo.withCallingConv(getCallingConventionForDecl(MD));
+
+ if (getContext().getLangOptions().ObjCAutoRefCount &&
+ MD->hasAttr<NSReturnsRetainedAttr>())
+ einfo = einfo.withProducesResult(true);
+
+ return getFunctionInfo(GetReturnType(MD->getResultType()), ArgTys, einfo);
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(GlobalDecl GD) {
@@ -240,8 +241,7 @@ const CGFunctionInfo &CodeGenTypes::getNullaryFunctionInfo() {
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(CanQualType ResTy,
const llvm::SmallVectorImpl<CanQualType> &ArgTys,
- const FunctionType::ExtInfo &Info,
- bool IsRecursive) {
+ const FunctionType::ExtInfo &Info) {
#ifndef NDEBUG
for (llvm::SmallVectorImpl<CanQualType>::const_iterator
I = ArgTys.begin(), E = ArgTys.end(); I != E; ++I)
@@ -252,8 +252,7 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(CanQualType ResTy,
// Lookup or create unique function info.
llvm::FoldingSetNodeID ID;
- CGFunctionInfo::Profile(ID, Info, ResTy,
- ArgTys.begin(), ArgTys.end());
+ CGFunctionInfo::Profile(ID, Info, ResTy, ArgTys.begin(), ArgTys.end());
void *InsertPos = 0;
CGFunctionInfo *FI = FunctionInfos.FindNodeOrInsertPos(ID, InsertPos);
@@ -261,10 +260,14 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(CanQualType ResTy,
return *FI;
// Construct the function info.
- FI = new CGFunctionInfo(CC, Info.getNoReturn(), Info.getHasRegParm(), Info.getRegParm(), ResTy,
+ FI = new CGFunctionInfo(CC, Info.getNoReturn(), Info.getProducesResult(),
+ Info.getHasRegParm(), Info.getRegParm(), ResTy,
ArgTys.data(), ArgTys.size());
FunctionInfos.InsertNode(FI, InsertPos);
+ bool Inserted = FunctionsBeingProcessed.insert(FI); (void)Inserted;
+ assert(Inserted && "Recursively being processed?");
+
// Compute ABI information.
getABIInfo().computeInfo(*FI);
@@ -273,30 +276,29 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(CanQualType ResTy,
// default now.
ABIArgInfo &RetInfo = FI->getReturnInfo();
if (RetInfo.canHaveCoerceToType() && RetInfo.getCoerceToType() == 0)
- RetInfo.setCoerceToType(ConvertTypeRecursive(FI->getReturnType()));
+ RetInfo.setCoerceToType(ConvertType(FI->getReturnType()));
for (CGFunctionInfo::arg_iterator I = FI->arg_begin(), E = FI->arg_end();
I != E; ++I)
if (I->info.canHaveCoerceToType() && I->info.getCoerceToType() == 0)
- I->info.setCoerceToType(ConvertTypeRecursive(I->type));
-
- // If this is a top-level call and ConvertTypeRecursive hit unresolved pointer
- // types, resolve them now. These pointers may point to this function, which
- // we *just* filled in the FunctionInfo for.
- if (!IsRecursive && !PointersToResolve.empty())
- HandleLateResolvedPointers();
+ I->info.setCoerceToType(ConvertType(I->type));
+ bool Erased = FunctionsBeingProcessed.erase(FI); (void)Erased;
+ assert(Erased && "Not in set?");
+
return *FI;
}
CGFunctionInfo::CGFunctionInfo(unsigned _CallingConvention,
- bool _NoReturn, bool _HasRegParm, unsigned _RegParm,
+ bool _NoReturn, bool returnsRetained,
+ bool _HasRegParm, unsigned _RegParm,
CanQualType ResTy,
const CanQualType *ArgTys,
unsigned NumArgTys)
: CallingConvention(_CallingConvention),
EffectiveCallingConvention(_CallingConvention),
- NoReturn(_NoReturn), HasRegParm(_HasRegParm), RegParm(_RegParm)
+ NoReturn(_NoReturn), ReturnsRetained(returnsRetained),
+ HasRegParm(_HasRegParm), RegParm(_RegParm)
{
NumArgs = NumArgTys;
@@ -310,8 +312,7 @@ CGFunctionInfo::CGFunctionInfo(unsigned _CallingConvention,
/***/
void CodeGenTypes::GetExpandedTypes(QualType type,
- llvm::SmallVectorImpl<const llvm::Type*> &expandedTypes,
- bool isRecursive) {
+ llvm::SmallVectorImpl<llvm::Type*> &expandedTypes) {
const RecordType *RT = type->getAsStructureType();
assert(RT && "Can only expand structure types.");
const RecordDecl *RD = RT->getDecl();
@@ -326,9 +327,9 @@ void CodeGenTypes::GetExpandedTypes(QualType type,
QualType fieldType = FD->getType();
if (fieldType->isRecordType())
- GetExpandedTypes(fieldType, expandedTypes, isRecursive);
+ GetExpandedTypes(fieldType, expandedTypes);
else
- expandedTypes.push_back(ConvertType(fieldType, isRecursive));
+ expandedTypes.push_back(ConvertType(fieldType));
}
}
@@ -352,7 +353,7 @@ CodeGenFunction::ExpandTypeFromArgs(QualType Ty, LValue LV,
if (CodeGenFunction::hasAggregateLLVMType(FT)) {
AI = ExpandTypeFromArgs(FT, LV, AI);
} else {
- EmitStoreThroughLValue(RValue::get(AI), LV, FT);
+ EmitStoreThroughLValue(RValue::get(AI), LV);
++AI;
}
}
@@ -360,33 +361,6 @@ CodeGenFunction::ExpandTypeFromArgs(QualType Ty, LValue LV,
return AI;
}
-void
-CodeGenFunction::ExpandTypeToArgs(QualType Ty, RValue RV,
- llvm::SmallVector<llvm::Value*, 16> &Args) {
- const RecordType *RT = Ty->getAsStructureType();
- assert(RT && "Can only expand structure types.");
-
- RecordDecl *RD = RT->getDecl();
- assert(RV.isAggregate() && "Unexpected rvalue during struct expansion");
- llvm::Value *Addr = RV.getAggregateAddr();
- for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
- i != e; ++i) {
- FieldDecl *FD = *i;
- QualType FT = FD->getType();
-
- // FIXME: What are the right qualifiers here?
- LValue LV = EmitLValueForField(Addr, FD, 0);
- if (CodeGenFunction::hasAggregateLLVMType(FT)) {
- ExpandTypeToArgs(FT, RValue::getAggregate(LV.getAddress()), Args);
- } else {
- RValue RV = EmitLoadOfLValue(LV, FT);
- assert(RV.isScalar() &&
- "Unexpected non-scalar rvalue during struct expansion.");
- Args.push_back(RV.getScalarVal());
- }
- }
-}
-
/// EnterStructPointerForCoercedAccess - Given a struct pointer that we are
/// accessing some number of bytes out of it, try to gep into the struct to get
/// at its inner goodness. Dive as deep as possible without entering an element
@@ -622,7 +596,7 @@ bool CodeGenModule::ReturnTypeUsesFPRet(QualType ResultType) {
return false;
}
-const llvm::FunctionType *CodeGenTypes::GetFunctionType(GlobalDecl GD) {
+llvm::FunctionType *CodeGenTypes::GetFunctionType(GlobalDecl GD) {
const CGFunctionInfo &FI = getFunctionInfo(GD);
// For definition purposes, don't consider a K&R function variadic.
@@ -631,13 +605,16 @@ const llvm::FunctionType *CodeGenTypes::GetFunctionType(GlobalDecl GD) {
cast<FunctionDecl>(GD.getDecl())->getType()->getAs<FunctionProtoType>())
Variadic = FPT->isVariadic();
- return GetFunctionType(FI, Variadic, false);
+ return GetFunctionType(FI, Variadic);
}
-const llvm::FunctionType *
-CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool isVariadic,
- bool isRecursive) {
- llvm::SmallVector<const llvm::Type*, 8> argTypes;
+llvm::FunctionType *
+CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool isVariadic) {
+
+ bool Inserted = FunctionsBeingProcessed.insert(&FI); (void)Inserted;
+ assert(Inserted && "Recursively being processed?");
+
+ llvm::SmallVector<llvm::Type*, 8> argTypes;
const llvm::Type *resultType = 0;
const ABIArgInfo &retAI = FI.getReturnInfo();
@@ -655,7 +632,7 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool isVariadic,
resultType = llvm::Type::getVoidTy(getLLVMContext());
QualType ret = FI.getReturnType();
- const llvm::Type *ty = ConvertType(ret, isRecursive);
+ const llvm::Type *ty = ConvertType(ret);
unsigned addressSpace = Context.getTargetAddressSpace(ret);
argTypes.push_back(llvm::PointerType::get(ty, addressSpace));
break;
@@ -676,7 +653,7 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool isVariadic,
case ABIArgInfo::Indirect: {
// indirect arguments are always on the stack, which is addr space #0.
- const llvm::Type *LTy = ConvertTypeForMem(it->type, isRecursive);
+ const llvm::Type *LTy = ConvertTypeForMem(it->type);
argTypes.push_back(LTy->getPointerTo());
break;
}
@@ -686,7 +663,7 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool isVariadic,
// If the coerce-to type is a first class aggregate, flatten it. Either
// way is semantically identical, but fast-isel and the optimizer
// generally likes scalar values better than FCAs.
- const llvm::Type *argType = argAI.getCoerceToType();
+ llvm::Type *argType = argAI.getCoerceToType();
if (const llvm::StructType *st = dyn_cast<llvm::StructType>(argType)) {
for (unsigned i = 0, e = st->getNumElements(); i != e; ++i)
argTypes.push_back(st->getElementType(i));
@@ -697,11 +674,14 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool isVariadic,
}
case ABIArgInfo::Expand:
- GetExpandedTypes(it->type, argTypes, isRecursive);
+ GetExpandedTypes(it->type, argTypes);
break;
}
}
+ bool Erased = FunctionsBeingProcessed.erase(&FI); (void)Erased;
+ assert(Erased && "Not in set?");
+
return llvm::FunctionType::get(resultType, argTypes, isVariadic);
}
@@ -709,16 +689,15 @@ const llvm::Type *CodeGenTypes::GetFunctionTypeForVTable(GlobalDecl GD) {
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
- if (!VerifyFuncTypeComplete(FPT)) {
- const CGFunctionInfo *Info;
- if (isa<CXXDestructorDecl>(MD))
- Info = &getFunctionInfo(cast<CXXDestructorDecl>(MD), GD.getDtorType());
- else
- Info = &getFunctionInfo(MD);
- return GetFunctionType(*Info, FPT->isVariadic(), false);
- }
-
- return llvm::OpaqueType::get(getLLVMContext());
+ if (!isFuncTypeConvertible(FPT))
+ return llvm::StructType::get(getLLVMContext());
+
+ const CGFunctionInfo *Info;
+ if (isa<CXXDestructorDecl>(MD))
+ Info = &getFunctionInfo(cast<CXXDestructorDecl>(MD), GD.getDtorType());
+ else
+ Info = &getFunctionInfo(MD);
+ return GetFunctionType(*Info, FPT->isVariadic());
}
void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
@@ -845,11 +824,11 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
continue;
case ABIArgInfo::Expand: {
- llvm::SmallVector<const llvm::Type*, 8> types;
+ llvm::SmallVector<llvm::Type*, 8> types;
// FIXME: This is rather inefficient. Do we ever actually need to do
// anything here? The result should be just reconstructed on the other
// side, so extension should be a non-issue.
- getTypes().GetExpandedTypes(ParamType, types, false);
+ getTypes().GetExpandedTypes(ParamType, types);
Index += types.size();
continue;
}
@@ -1067,6 +1046,95 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
assert(AI == Fn->arg_end() && "Argument mismatch!");
}
+/// Try to emit a fused autorelease of a return result.
+static llvm::Value *tryEmitFusedAutoreleaseOfResult(CodeGenFunction &CGF,
+ llvm::Value *result) {
+ // We must be immediately followed the cast.
+ llvm::BasicBlock *BB = CGF.Builder.GetInsertBlock();
+ if (BB->empty()) return 0;
+ if (&BB->back() != result) return 0;
+
+ const llvm::Type *resultType = result->getType();
+
+ // result is in a BasicBlock and is therefore an Instruction.
+ llvm::Instruction *generator = cast<llvm::Instruction>(result);
+
+ llvm::SmallVector<llvm::Instruction*,4> insnsToKill;
+
+ // Look for:
+ // %generator = bitcast %type1* %generator2 to %type2*
+ while (llvm::BitCastInst *bitcast = dyn_cast<llvm::BitCastInst>(generator)) {
+ // We would have emitted this as a constant if the operand weren't
+ // an Instruction.
+ generator = cast<llvm::Instruction>(bitcast->getOperand(0));
+
+ // Require the generator to be immediately followed by the cast.
+ if (generator->getNextNode() != bitcast)
+ return 0;
+
+ insnsToKill.push_back(bitcast);
+ }
+
+ // Look for:
+ // %generator = call i8* @objc_retain(i8* %originalResult)
+ // or
+ // %generator = call i8* @objc_retainAutoreleasedReturnValue(i8* %originalResult)
+ llvm::CallInst *call = dyn_cast<llvm::CallInst>(generator);
+ if (!call) return 0;
+
+ bool doRetainAutorelease;
+
+ if (call->getCalledValue() == CGF.CGM.getARCEntrypoints().objc_retain) {
+ doRetainAutorelease = true;
+ } else if (call->getCalledValue() == CGF.CGM.getARCEntrypoints()
+ .objc_retainAutoreleasedReturnValue) {
+ doRetainAutorelease = false;
+
+ // Look for an inline asm immediately preceding the call and kill it, too.
+ llvm::Instruction *prev = call->getPrevNode();
+ if (llvm::CallInst *asmCall = dyn_cast_or_null<llvm::CallInst>(prev))
+ if (asmCall->getCalledValue()
+ == CGF.CGM.getARCEntrypoints().retainAutoreleasedReturnValueMarker)
+ insnsToKill.push_back(prev);
+ } else {
+ return 0;
+ }
+
+ result = call->getArgOperand(0);
+ insnsToKill.push_back(call);
+
+ // Keep killing bitcasts, for sanity. Note that we no longer care
+ // about precise ordering as long as there's exactly one use.
+ while (llvm::BitCastInst *bitcast = dyn_cast<llvm::BitCastInst>(result)) {
+ if (!bitcast->hasOneUse()) break;
+ insnsToKill.push_back(bitcast);
+ result = bitcast->getOperand(0);
+ }
+
+ // Delete all the unnecessary instructions, from latest to earliest.
+ for (llvm::SmallVectorImpl<llvm::Instruction*>::iterator
+ i = insnsToKill.begin(), e = insnsToKill.end(); i != e; ++i)
+ (*i)->eraseFromParent();
+
+ // Do the fused retain/autorelease if we were asked to.
+ if (doRetainAutorelease)
+ result = CGF.EmitARCRetainAutoreleaseReturnValue(result);
+
+ // Cast back to the result type.
+ return CGF.Builder.CreateBitCast(result, resultType);
+}
+
+/// Emit an ARC autorelease of the result of a function.
+static llvm::Value *emitAutoreleaseOfResult(CodeGenFunction &CGF,
+ llvm::Value *result) {
+ // At -O0, try to emit a fused retain/autorelease.
+ if (CGF.shouldUseFusedARCCalls())
+ if (llvm::Value *fused = tryEmitFusedAutoreleaseOfResult(CGF, result))
+ return fused;
+
+ return CGF.EmitARCAutoreleaseReturnValue(result);
+}
+
void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI) {
// Functions with no result always return void.
if (ReturnValue == 0) {
@@ -1134,6 +1202,16 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI) {
RV = CreateCoercedLoad(V, RetAI.getCoerceToType(), *this);
}
+
+ // In ARC, end functions that return a retainable type with a call
+ // to objc_autoreleaseReturnValue.
+ if (AutoreleaseResult) {
+ assert(getLangOptions().ObjCAutoRefCount &&
+ !FI.isReturnsRetained() &&
+ RetTy->isObjCRetainableType());
+ RV = emitAutoreleaseOfResult(*this, RV);
+ }
+
break;
case ABIArgInfo::Ignore:
@@ -1183,13 +1261,157 @@ void CodeGenFunction::EmitDelegateCallArg(CallArgList &args,
return args.add(RValue::get(value), type);
}
+static bool isProvablyNull(llvm::Value *addr) {
+ return isa<llvm::ConstantPointerNull>(addr);
+}
+
+static bool isProvablyNonNull(llvm::Value *addr) {
+ return isa<llvm::AllocaInst>(addr);
+}
+
+/// Emit the actual writing-back of a writeback.
+static void emitWriteback(CodeGenFunction &CGF,
+ const CallArgList::Writeback &writeback) {
+ llvm::Value *srcAddr = writeback.Address;
+ assert(!isProvablyNull(srcAddr) &&
+ "shouldn't have writeback for provably null argument");
+
+ llvm::BasicBlock *contBB = 0;
+
+ // If the argument wasn't provably non-null, we need to null check
+ // before doing the store.
+ bool provablyNonNull = isProvablyNonNull(srcAddr);
+ if (!provablyNonNull) {
+ llvm::BasicBlock *writebackBB = CGF.createBasicBlock("icr.writeback");
+ contBB = CGF.createBasicBlock("icr.done");
+
+ llvm::Value *isNull = CGF.Builder.CreateIsNull(srcAddr, "icr.isnull");
+ CGF.Builder.CreateCondBr(isNull, contBB, writebackBB);
+ CGF.EmitBlock(writebackBB);
+ }
+
+ // Load the value to writeback.
+ llvm::Value *value = CGF.Builder.CreateLoad(writeback.Temporary);
+
+ // Cast it back, in case we're writing an id to a Foo* or something.
+ value = CGF.Builder.CreateBitCast(value,
+ cast<llvm::PointerType>(srcAddr->getType())->getElementType(),
+ "icr.writeback-cast");
+
+ // Perform the writeback.
+ QualType srcAddrType = writeback.AddressType;
+ CGF.EmitStoreThroughLValue(RValue::get(value),
+ CGF.MakeAddrLValue(srcAddr, srcAddrType));
+
+ // Jump to the continuation block.
+ if (!provablyNonNull)
+ CGF.EmitBlock(contBB);
+}
+
+static void emitWritebacks(CodeGenFunction &CGF,
+ const CallArgList &args) {
+ for (CallArgList::writeback_iterator
+ i = args.writeback_begin(), e = args.writeback_end(); i != e; ++i)
+ emitWriteback(CGF, *i);
+}
+
+/// Emit an argument that's being passed call-by-writeback. That is,
+/// we are passing the address of
+static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args,
+ const ObjCIndirectCopyRestoreExpr *CRE) {
+ llvm::Value *srcAddr = CGF.EmitScalarExpr(CRE->getSubExpr());
+
+ // The dest and src types don't necessarily match in LLVM terms
+ // because of the crazy ObjC compatibility rules.
+
+ const llvm::PointerType *destType =
+ cast<llvm::PointerType>(CGF.ConvertType(CRE->getType()));
+
+ // If the address is a constant null, just pass the appropriate null.
+ if (isProvablyNull(srcAddr)) {
+ args.add(RValue::get(llvm::ConstantPointerNull::get(destType)),
+ CRE->getType());
+ return;
+ }
+
+ QualType srcAddrType =
+ CRE->getSubExpr()->getType()->castAs<PointerType>()->getPointeeType();
+
+ // Create the temporary.
+ llvm::Value *temp = CGF.CreateTempAlloca(destType->getElementType(),
+ "icr.temp");
+
+ // Zero-initialize it if we're not doing a copy-initialization.
+ bool shouldCopy = CRE->shouldCopy();
+ if (!shouldCopy) {
+ llvm::Value *null =
+ llvm::ConstantPointerNull::get(
+ cast<llvm::PointerType>(destType->getElementType()));
+ CGF.Builder.CreateStore(null, temp);
+ }
+
+ llvm::BasicBlock *contBB = 0;
+
+ // If the address is *not* known to be non-null, we need to switch.
+ llvm::Value *finalArgument;
+
+ bool provablyNonNull = isProvablyNonNull(srcAddr);
+ if (provablyNonNull) {
+ finalArgument = temp;
+ } else {
+ llvm::Value *isNull = CGF.Builder.CreateIsNull(srcAddr, "icr.isnull");
+
+ finalArgument = CGF.Builder.CreateSelect(isNull,
+ llvm::ConstantPointerNull::get(destType),
+ temp, "icr.argument");
+
+ // If we need to copy, then the load has to be conditional, which
+ // means we need control flow.
+ if (shouldCopy) {
+ contBB = CGF.createBasicBlock("icr.cont");
+ llvm::BasicBlock *copyBB = CGF.createBasicBlock("icr.copy");
+ CGF.Builder.CreateCondBr(isNull, contBB, copyBB);
+ CGF.EmitBlock(copyBB);
+ }
+ }
+
+ // Perform a copy if necessary.
+ if (shouldCopy) {
+ LValue srcLV = CGF.MakeAddrLValue(srcAddr, srcAddrType);
+ RValue srcRV = CGF.EmitLoadOfLValue(srcLV);
+ assert(srcRV.isScalar());
+
+ llvm::Value *src = srcRV.getScalarVal();
+ src = CGF.Builder.CreateBitCast(src, destType->getElementType(),
+ "icr.cast");
+
+ // Use an ordinary store, not a store-to-lvalue.
+ CGF.Builder.CreateStore(src, temp);
+ }
+
+ // Finish the control flow if we needed it.
+ if (shouldCopy && !provablyNonNull)
+ CGF.EmitBlock(contBB);
+
+ args.addWriteback(srcAddr, srcAddrType, temp);
+ args.add(RValue::get(finalArgument), CRE->getType());
+}
+
void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E,
QualType type) {
+ if (const ObjCIndirectCopyRestoreExpr *CRE
+ = dyn_cast<ObjCIndirectCopyRestoreExpr>(E)) {
+ assert(getContext().getLangOptions().ObjCAutoRefCount);
+ assert(getContext().hasSameType(E->getType(), type));
+ return emitWritebackArg(*this, args, CRE);
+ }
+
if (type->isReferenceType())
return args.add(EmitReferenceBindingToExpr(E, /*InitializedDecl=*/0),
type);
- if (hasAggregateLLVMType(type) && isa<ImplicitCastExpr>(E) &&
+ if (hasAggregateLLVMType(type) && !E->getType()->isAnyComplexType() &&
+ isa<ImplicitCastExpr>(E) &&
cast<CastExpr>(E)->getCastKind() == CK_LValueToRValue) {
LValue L = EmitLValue(cast<CastExpr>(E)->getSubExpr());
assert(L.isSimple());
@@ -1205,20 +1427,71 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E,
/// on the current state of the EH stack.
llvm::CallSite
CodeGenFunction::EmitCallOrInvoke(llvm::Value *Callee,
- llvm::Value * const *ArgBegin,
- llvm::Value * const *ArgEnd,
+ llvm::ArrayRef<llvm::Value *> Args,
const llvm::Twine &Name) {
llvm::BasicBlock *InvokeDest = getInvokeDest();
if (!InvokeDest)
- return Builder.CreateCall(Callee, ArgBegin, ArgEnd, Name);
+ return Builder.CreateCall(Callee, Args, Name);
llvm::BasicBlock *ContBB = createBasicBlock("invoke.cont");
llvm::InvokeInst *Invoke = Builder.CreateInvoke(Callee, ContBB, InvokeDest,
- ArgBegin, ArgEnd, Name);
+ Args, Name);
EmitBlock(ContBB);
return Invoke;
}
+llvm::CallSite
+CodeGenFunction::EmitCallOrInvoke(llvm::Value *Callee,
+ const llvm::Twine &Name) {
+ return EmitCallOrInvoke(Callee, llvm::ArrayRef<llvm::Value *>(), Name);
+}
+
+static void checkArgMatches(llvm::Value *Elt, unsigned &ArgNo,
+ llvm::FunctionType *FTy) {
+ if (ArgNo < FTy->getNumParams())
+ assert(Elt->getType() == FTy->getParamType(ArgNo));
+ else
+ assert(FTy->isVarArg());
+ ++ArgNo;
+}
+
+void CodeGenFunction::ExpandTypeToArgs(QualType Ty, RValue RV,
+ llvm::SmallVector<llvm::Value*,16> &Args,
+ llvm::FunctionType *IRFuncTy) {
+ const RecordType *RT = Ty->getAsStructureType();
+ assert(RT && "Can only expand structure types.");
+
+ RecordDecl *RD = RT->getDecl();
+ assert(RV.isAggregate() && "Unexpected rvalue during struct expansion");
+ llvm::Value *Addr = RV.getAggregateAddr();
+ for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
+ i != e; ++i) {
+ FieldDecl *FD = *i;
+ QualType FT = FD->getType();
+
+ // FIXME: What are the right qualifiers here?
+ LValue LV = EmitLValueForField(Addr, FD, 0);
+ if (CodeGenFunction::hasAggregateLLVMType(FT)) {
+ ExpandTypeToArgs(FT, RValue::getAggregate(LV.getAddress()),
+ Args, IRFuncTy);
+ continue;
+ }
+
+ RValue RV = EmitLoadOfLValue(LV);
+ assert(RV.isScalar() &&
+ "Unexpected non-scalar rvalue during struct expansion.");
+
+ // Insert a bitcast as needed.
+ llvm::Value *V = RV.getScalarVal();
+ if (Args.size() < IRFuncTy->getNumParams() &&
+ V->getType() != IRFuncTy->getParamType(Args.size()))
+ V = Builder.CreateBitCast(V, IRFuncTy->getParamType(Args.size()));
+
+ Args.push_back(V);
+ }
+}
+
+
RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
llvm::Value *Callee,
ReturnValueSlot ReturnValue,
@@ -1233,6 +1506,11 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
QualType RetTy = CallInfo.getReturnType();
const ABIArgInfo &RetAI = CallInfo.getReturnInfo();
+ // IRArgNo - Keep track of the argument number in the callee we're looking at.
+ unsigned IRArgNo = 0;
+ llvm::FunctionType *IRFuncTy =
+ cast<llvm::FunctionType>(
+ cast<llvm::PointerType>(Callee->getType())->getElementType());
// If the call returns a temporary with struct return, create a temporary
// alloca to hold the result, unless one is given to us.
@@ -1241,6 +1519,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
if (!Value)
Value = CreateMemTemp(RetTy);
Args.push_back(Value);
+ checkArgMatches(Value, IRArgNo, IRFuncTy);
}
assert(CallInfo.arg_size() == CallArgs.size() &&
@@ -1251,24 +1530,54 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
const ABIArgInfo &ArgInfo = info_it->info;
RValue RV = I->RV;
- unsigned Alignment =
+ unsigned TypeAlign =
getContext().getTypeAlignInChars(I->Ty).getQuantity();
switch (ArgInfo.getKind()) {
case ABIArgInfo::Indirect: {
if (RV.isScalar() || RV.isComplex()) {
// Make a temporary alloca to pass the argument.
- Args.push_back(CreateMemTemp(I->Ty));
+ llvm::AllocaInst *AI = CreateMemTemp(I->Ty);
+ if (ArgInfo.getIndirectAlign() > AI->getAlignment())
+ AI->setAlignment(ArgInfo.getIndirectAlign());
+ Args.push_back(AI);
+
if (RV.isScalar())
EmitStoreOfScalar(RV.getScalarVal(), Args.back(), false,
- Alignment, I->Ty);
+ TypeAlign, I->Ty);
else
StoreComplexToAddr(RV.getComplexVal(), Args.back(), false);
- } else if (I->NeedsCopy && !ArgInfo.getIndirectByVal()) {
- Args.push_back(CreateMemTemp(I->Ty));
- EmitAggregateCopy(Args.back(), RV.getAggregateAddr(), I->Ty,
- RV.isVolatileQualified());
+
+ // Validate argument match.
+ checkArgMatches(AI, IRArgNo, IRFuncTy);
} else {
- Args.push_back(RV.getAggregateAddr());
+ // We want to avoid creating an unnecessary temporary+copy here;
+ // however, we need one in two cases:
+ // 1. If the argument is not byval, and we are required to copy the
+ // source. (This case doesn't occur on any common architecture.)
+ // 2. If the argument is byval, RV is not sufficiently aligned, and
+ // we cannot force it to be sufficiently aligned.
+ llvm::Value *Addr = RV.getAggregateAddr();
+ unsigned Align = ArgInfo.getIndirectAlign();
+ const llvm::TargetData *TD = &CGM.getTargetData();
+ if ((!ArgInfo.getIndirectByVal() && I->NeedsCopy) ||
+ (ArgInfo.getIndirectByVal() && TypeAlign < Align &&
+ llvm::getOrEnforceKnownAlignment(Addr, Align, TD) < Align)) {
+ // Create an aligned temporary, and copy to it.
+ llvm::AllocaInst *AI = CreateMemTemp(I->Ty);
+ if (Align > AI->getAlignment())
+ AI->setAlignment(Align);
+ Args.push_back(AI);
+ EmitAggregateCopy(AI, Addr, I->Ty, RV.isVolatileQualified());
+
+ // Validate argument match.
+ checkArgMatches(AI, IRArgNo, IRFuncTy);
+ } else {
+ // Skip the extra memcpy call.
+ Args.push_back(Addr);
+
+ // Validate argument match.
+ checkArgMatches(Addr, IRArgNo, IRFuncTy);
+ }
}
break;
}
@@ -1281,10 +1590,20 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
if (!isa<llvm::StructType>(ArgInfo.getCoerceToType()) &&
ArgInfo.getCoerceToType() == ConvertType(info_it->type) &&
ArgInfo.getDirectOffset() == 0) {
+ llvm::Value *V;
if (RV.isScalar())
- Args.push_back(RV.getScalarVal());
+ V = RV.getScalarVal();
else
- Args.push_back(Builder.CreateLoad(RV.getAggregateAddr()));
+ V = Builder.CreateLoad(RV.getAggregateAddr());
+
+ // If the argument doesn't match, perform a bitcast to coerce it. This
+ // can happen due to trivial type mismatches.
+ if (IRArgNo < IRFuncTy->getNumParams() &&
+ V->getType() != IRFuncTy->getParamType(IRArgNo))
+ V = Builder.CreateBitCast(V, IRFuncTy->getParamType(IRArgNo));
+ Args.push_back(V);
+
+ checkArgMatches(V, IRArgNo, IRFuncTy);
break;
}
@@ -1292,7 +1611,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
llvm::Value *SrcPtr;
if (RV.isScalar()) {
SrcPtr = CreateMemTemp(I->Ty, "coerce");
- EmitStoreOfScalar(RV.getScalarVal(), SrcPtr, false, Alignment, I->Ty);
+ EmitStoreOfScalar(RV.getScalarVal(), SrcPtr, false, TypeAlign, I->Ty);
} else if (RV.isComplex()) {
SrcPtr = CreateMemTemp(I->Ty, "coerce");
StoreComplexToAddr(RV.getComplexVal(), SrcPtr, false);
@@ -1321,18 +1640,25 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
// We don't know what we're loading from.
LI->setAlignment(1);
Args.push_back(LI);
+
+ // Validate argument match.
+ checkArgMatches(LI, IRArgNo, IRFuncTy);
}
} else {
// In the simple case, just pass the coerced loaded value.
Args.push_back(CreateCoercedLoad(SrcPtr, ArgInfo.getCoerceToType(),
*this));
+
+ // Validate argument match.
+ checkArgMatches(Args.back(), IRArgNo, IRFuncTy);
}
break;
}
case ABIArgInfo::Expand:
- ExpandTypeToArgs(I->Ty, RV, Args);
+ ExpandTypeToArgs(I->Ty, RV, Args, IRFuncTy);
+ IRArgNo = Args.size();
break;
}
}
@@ -1367,7 +1693,6 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
}
}
-
unsigned CallingConv;
CodeGen::AttributeListType AttributeList;
CGM.ConstructAttributeList(CallInfo, TargetDecl, AttributeList, CallingConv);
@@ -1380,11 +1705,10 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
llvm::CallSite CS;
if (!InvokeDest) {
- CS = Builder.CreateCall(Callee, Args.data(), Args.data()+Args.size());
+ CS = Builder.CreateCall(Callee, Args);
} else {
llvm::BasicBlock *Cont = createBasicBlock("invoke.cont");
- CS = Builder.CreateInvoke(Callee, Cont, InvokeDest,
- Args.data(), Args.data()+Args.size());
+ CS = Builder.CreateInvoke(Callee, Cont, InvokeDest, Args);
EmitBlock(Cont);
}
if (callOrInvoke)
@@ -1413,6 +1737,11 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
if (Builder.isNamePreserving() && !CI->getType()->isVoidTy())
CI->setName("call");
+ // Emit any writebacks immediately. Arguably this should happen
+ // after any return-value munging.
+ if (CallArgs.hasWritebacks())
+ emitWritebacks(*this, CallArgs);
+
switch (RetAI.getKind()) {
case ABIArgInfo::Indirect: {
unsigned Alignment = getContext().getTypeAlignInChars(RetTy).getQuantity();
@@ -1430,8 +1759,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
case ABIArgInfo::Extend:
case ABIArgInfo::Direct: {
- if (RetAI.getCoerceToType() == ConvertType(RetTy) &&
- RetAI.getDirectOffset() == 0) {
+ llvm::Type *RetIRTy = ConvertType(RetTy);
+ if (RetAI.getCoerceToType() == RetIRTy && RetAI.getDirectOffset() == 0) {
if (RetTy->isAnyComplexType()) {
llvm::Value *Real = Builder.CreateExtractValue(CI, 0);
llvm::Value *Imag = Builder.CreateExtractValue(CI, 1);
@@ -1448,7 +1777,13 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
BuildAggStore(*this, CI, DestPtr, DestIsVolatile, false);
return RValue::getAggregate(DestPtr);
}
- return RValue::get(CI);
+
+ // If the argument doesn't match, perform a bitcast to coerce it. This
+ // can happen due to trivial type mismatches.
+ llvm::Value *V = CI;
+ if (V->getType() != RetIRTy)
+ V = Builder.CreateBitCast(V, RetIRTy);
+ return RValue::get(V);
}
llvm::Value *DestPtr = ReturnValue.getValue();
diff --git a/lib/CodeGen/CGCall.h b/lib/CodeGen/CGCall.h
index 160a62eab367..343b944bf6c9 100644
--- a/lib/CodeGen/CGCall.h
+++ b/lib/CodeGen/CGCall.h
@@ -58,9 +58,44 @@ namespace CodeGen {
class CallArgList :
public llvm::SmallVector<CallArg, 16> {
public:
+ struct Writeback {
+ /// The original argument.
+ llvm::Value *Address;
+
+ /// The pointee type of the original argument.
+ QualType AddressType;
+
+ /// The temporary alloca.
+ llvm::Value *Temporary;
+ };
+
void add(RValue rvalue, QualType type, bool needscopy = false) {
push_back(CallArg(rvalue, type, needscopy));
}
+
+ void addFrom(const CallArgList &other) {
+ insert(end(), other.begin(), other.end());
+ Writebacks.insert(Writebacks.end(),
+ other.Writebacks.begin(), other.Writebacks.end());
+ }
+
+ void addWriteback(llvm::Value *address, QualType addressType,
+ llvm::Value *temporary) {
+ Writeback writeback;
+ writeback.Address = address;
+ writeback.AddressType = addressType;
+ writeback.Temporary = temporary;
+ Writebacks.push_back(writeback);
+ }
+
+ bool hasWritebacks() const { return !Writebacks.empty(); }
+
+ typedef llvm::SmallVectorImpl<Writeback>::const_iterator writeback_iterator;
+ writeback_iterator writeback_begin() const { return Writebacks.begin(); }
+ writeback_iterator writeback_end() const { return Writebacks.end(); }
+
+ private:
+ llvm::SmallVector<Writeback, 1> Writebacks;
};
/// FunctionArgList - Type for representing both the decl and type
@@ -88,6 +123,9 @@ namespace CodeGen {
/// Whether this function is noreturn.
bool NoReturn;
+ /// Whether this function is returns-retained.
+ bool ReturnsRetained;
+
unsigned NumArgs;
ArgInfo *Args;
@@ -100,7 +138,8 @@ namespace CodeGen {
typedef ArgInfo *arg_iterator;
CGFunctionInfo(unsigned CallingConvention, bool NoReturn,
- bool HasRegParm, unsigned RegParm, CanQualType ResTy,
+ bool ReturnsRetained, bool HasRegParm, unsigned RegParm,
+ CanQualType ResTy,
const CanQualType *ArgTys, unsigned NumArgTys);
~CGFunctionInfo() { delete[] Args; }
@@ -113,6 +152,10 @@ namespace CodeGen {
bool isNoReturn() const { return NoReturn; }
+ /// In ARR, whether this function retains its return value. This
+ /// is not always reliable for call sites.
+ bool isReturnsRetained() const { return ReturnsRetained; }
+
/// getCallingConvention - Return the user specified calling
/// convention.
unsigned getCallingConvention() const { return CallingConvention; }
@@ -137,6 +180,7 @@ namespace CodeGen {
void Profile(llvm::FoldingSetNodeID &ID) {
ID.AddInteger(getCallingConvention());
ID.AddBoolean(NoReturn);
+ ID.AddBoolean(ReturnsRetained);
ID.AddBoolean(HasRegParm);
ID.AddInteger(RegParm);
getReturnType().Profile(ID);
@@ -151,6 +195,7 @@ namespace CodeGen {
Iterator end) {
ID.AddInteger(Info.getCC());
ID.AddBoolean(Info.getNoReturn());
+ ID.AddBoolean(Info.getProducesResult());
ID.AddBoolean(Info.getHasRegParm());
ID.AddInteger(Info.getRegParm());
ResTy.Profile(ID);
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index 5725d80b7d03..7dbaaf85299f 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -329,7 +329,7 @@ namespace {
CallBaseDtor(const CXXRecordDecl *Base, bool BaseIsVirtual)
: BaseClass(Base), BaseIsVirtual(BaseIsVirtual) {}
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
const CXXRecordDecl *DerivedClass =
cast<CXXMethodDecl>(CGF.CurCodeDecl)->getParent();
@@ -398,7 +398,8 @@ static void EmitBaseInitializer(CodeGenFunction &CGF,
BaseClassDecl,
isBaseVirtual);
- AggValueSlot AggSlot = AggValueSlot::forAddr(V, false, /*Lifetime*/ true);
+ AggValueSlot AggSlot = AggValueSlot::forAddr(V, Qualifiers(),
+ /*Lifetime*/ true);
CGF.EmitAggExpr(BaseInit->getInit(), AggSlot);
@@ -428,10 +429,18 @@ static void EmitAggMemberInitializer(CodeGenFunction &CGF,
CGF.Builder.CreateStore(Next, ArrayIndexVar);
}
- AggValueSlot Slot = AggValueSlot::forAddr(Dest, LHS.isVolatileQualified(),
- /*Lifetime*/ true);
-
- CGF.EmitAggExpr(MemberInit->getInit(), Slot);
+ if (!CGF.hasAggregateLLVMType(T)) {
+ LValue lvalue = CGF.MakeAddrLValue(Dest, T);
+ CGF.EmitScalarInit(MemberInit->getInit(), /*decl*/ 0, lvalue, false);
+ } else if (T->isAnyComplexType()) {
+ CGF.EmitComplexExprIntoAddr(MemberInit->getInit(), Dest,
+ LHS.isVolatileQualified());
+ } else {
+ AggValueSlot Slot = AggValueSlot::forAddr(Dest, LHS.getQuals(),
+ /*Lifetime*/ true);
+
+ CGF.EmitAggExpr(MemberInit->getInit(), Slot);
+ }
return;
}
@@ -502,7 +511,7 @@ namespace {
CallMemberDtor(FieldDecl *Field, CXXDestructorDecl *Dtor)
: Field(Field), Dtor(Dtor) {}
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
// FIXME: Is this OK for C++0x delegating constructors?
llvm::Value *ThisPtr = CGF.LoadCXXThis();
LValue LHS = CGF.EmitLValueForField(ThisPtr, Field, 0);
@@ -540,15 +549,15 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
// FIXME: If there's no initializer and the CXXCtorInitializer
// was implicitly generated, we shouldn't be zeroing memory.
- RValue RHS;
- if (FieldType->isReferenceType()) {
- RHS = CGF.EmitReferenceBindingToExpr(MemberInit->getInit(), Field);
- CGF.EmitStoreThroughLValue(RHS, LHS, FieldType);
- } else if (FieldType->isArrayType() && !MemberInit->getInit()) {
+ if (FieldType->isArrayType() && !MemberInit->getInit()) {
CGF.EmitNullInitialization(LHS.getAddress(), Field->getType());
} else if (!CGF.hasAggregateLLVMType(Field->getType())) {
- RHS = RValue::get(CGF.EmitScalarExpr(MemberInit->getInit()));
- CGF.EmitStoreThroughLValue(RHS, LHS, FieldType);
+ if (LHS.isSimple()) {
+ CGF.EmitExprAsInit(MemberInit->getInit(), Field, LHS, false);
+ } else {
+ RValue RHS = RValue::get(CGF.EmitScalarExpr(MemberInit->getInit()));
+ CGF.EmitStoreThroughLValue(RHS, LHS);
+ }
} else if (MemberInit->getInit()->getType()->isAnyComplexType()) {
CGF.EmitComplexExprIntoAddr(MemberInit->getInit(), LHS.getAddress(),
LHS.isVolatileQualified());
@@ -576,11 +585,11 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
llvm::Value *Zero = llvm::Constant::getNullValue(SizeTy);
CGF.Builder.CreateStore(Zero, ArrayIndexVar);
- // If we are copying an array of scalars or classes with trivial copy
+ // If we are copying an array of PODs or classes with trivial copy
// constructors, perform a single aggregate copy.
- const RecordType *Record = BaseElementTy->getAs<RecordType>();
- if (!Record ||
- cast<CXXRecordDecl>(Record->getDecl())->hasTrivialCopyConstructor()) {
+ const CXXRecordDecl *Record = BaseElementTy->getAsCXXRecordDecl();
+ if (BaseElementTy.isPODType(CGF.getContext()) ||
+ (Record && Record->hasTrivialCopyConstructor())) {
// Find the source pointer. We knows it's the last argument because
// we know we're in a copy constructor.
unsigned SrcArgIndex = Args.size() - 1;
@@ -912,7 +921,7 @@ namespace {
struct CallDtorDelete : EHScopeStack::Cleanup {
CallDtorDelete() {}
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CGF.CurCodeDecl);
const CXXRecordDecl *ClassDecl = Dtor->getParent();
CGF.EmitDeleteCall(Dtor->getOperatorDelete(), CGF.LoadCXXThis(),
@@ -920,48 +929,25 @@ namespace {
}
};
- struct CallArrayFieldDtor : EHScopeStack::Cleanup {
- const FieldDecl *Field;
- CallArrayFieldDtor(const FieldDecl *Field) : Field(Field) {}
-
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
- QualType FieldType = Field->getType();
- const ConstantArrayType *Array =
- CGF.getContext().getAsConstantArrayType(FieldType);
+ class DestroyField : public EHScopeStack::Cleanup {
+ const FieldDecl *field;
+ CodeGenFunction::Destroyer &destroyer;
+ bool useEHCleanupForArray;
+
+ public:
+ DestroyField(const FieldDecl *field, CodeGenFunction::Destroyer *destroyer,
+ bool useEHCleanupForArray)
+ : field(field), destroyer(*destroyer),
+ useEHCleanupForArray(useEHCleanupForArray) {}
+
+ void Emit(CodeGenFunction &CGF, Flags flags) {
+ // Find the address of the field.
+ llvm::Value *thisValue = CGF.LoadCXXThis();
+ LValue LV = CGF.EmitLValueForField(thisValue, field, /*CVRQualifiers=*/0);
+ assert(LV.isSimple());
- QualType BaseType =
- CGF.getContext().getBaseElementType(Array->getElementType());
- const CXXRecordDecl *FieldClassDecl = BaseType->getAsCXXRecordDecl();
-
- llvm::Value *ThisPtr = CGF.LoadCXXThis();
- LValue LHS = CGF.EmitLValueForField(ThisPtr, Field,
- // FIXME: Qualifiers?
- /*CVRQualifiers=*/0);
-
- const llvm::Type *BasePtr = CGF.ConvertType(BaseType)->getPointerTo();
- llvm::Value *BaseAddrPtr =
- CGF.Builder.CreateBitCast(LHS.getAddress(), BasePtr);
- CGF.EmitCXXAggrDestructorCall(FieldClassDecl->getDestructor(),
- Array, BaseAddrPtr);
- }
- };
-
- struct CallFieldDtor : EHScopeStack::Cleanup {
- const FieldDecl *Field;
- CallFieldDtor(const FieldDecl *Field) : Field(Field) {}
-
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
- const CXXRecordDecl *FieldClassDecl =
- Field->getType()->getAsCXXRecordDecl();
-
- llvm::Value *ThisPtr = CGF.LoadCXXThis();
- LValue LHS = CGF.EmitLValueForField(ThisPtr, Field,
- // FIXME: Qualifiers?
- /*CVRQualifiers=*/0);
-
- CGF.EmitCXXDestructorCall(FieldClassDecl->getDestructor(),
- Dtor_Complete, /*ForVirtualBase=*/false,
- LHS.getAddress());
+ CGF.emitDestroy(LV.getAddress(), field->getType(), destroyer,
+ flags.isForNormalCleanup() && useEHCleanupForArray);
}
};
}
@@ -1035,96 +1021,103 @@ void CodeGenFunction::EnterDtorCleanups(const CXXDestructorDecl *DD,
llvm::SmallVector<const FieldDecl *, 16> FieldDecls;
for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(),
E = ClassDecl->field_end(); I != E; ++I) {
- const FieldDecl *Field = *I;
-
- QualType FieldType = getContext().getCanonicalType(Field->getType());
- const ConstantArrayType *Array =
- getContext().getAsConstantArrayType(FieldType);
- if (Array)
- FieldType = getContext().getBaseElementType(Array->getElementType());
-
- const RecordType *RT = FieldType->getAs<RecordType>();
- if (!RT)
- continue;
-
- CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
- if (FieldClassDecl->hasTrivialDestructor())
- continue;
-
- if (Array)
- EHStack.pushCleanup<CallArrayFieldDtor>(NormalAndEHCleanup, Field);
- else
- EHStack.pushCleanup<CallFieldDtor>(NormalAndEHCleanup, Field);
+ const FieldDecl *field = *I;
+ QualType type = field->getType();
+ QualType::DestructionKind dtorKind = type.isDestructedType();
+ if (!dtorKind) continue;
+
+ CleanupKind cleanupKind = getCleanupKind(dtorKind);
+ EHStack.pushCleanup<DestroyField>(cleanupKind, field,
+ getDestroyer(dtorKind),
+ cleanupKind & EHCleanup);
}
}
-/// EmitCXXAggrConstructorCall - This routine essentially creates a (nested)
-/// for-loop to call the default constructor on individual members of the
-/// array.
-/// 'D' is the default constructor for elements of the array, 'ArrayTy' is the
-/// array type and 'ArrayPtr' points to the beginning fo the array.
-/// It is assumed that all relevant checks have been made by the caller.
+/// EmitCXXAggrConstructorCall - Emit a loop to call a particular
+/// constructor for each of several members of an array.
///
-/// \param ZeroInitialization True if each element should be zero-initialized
-/// before it is constructed.
+/// \param ctor the constructor to call for each element
+/// \param argBegin,argEnd the arguments to evaluate and pass to the
+/// constructor
+/// \param arrayType the type of the array to initialize
+/// \param arrayBegin an arrayType*
+/// \param zeroInitialize true if each element should be
+/// zero-initialized before it is constructed
void
-CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D,
- const ConstantArrayType *ArrayTy,
- llvm::Value *ArrayPtr,
- CallExpr::const_arg_iterator ArgBeg,
- CallExpr::const_arg_iterator ArgEnd,
- bool ZeroInitialization) {
-
- const llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
- llvm::Value * NumElements =
- llvm::ConstantInt::get(SizeTy,
- getContext().getConstantArrayElementCount(ArrayTy));
-
- EmitCXXAggrConstructorCall(D, NumElements, ArrayPtr, ArgBeg, ArgEnd,
- ZeroInitialization);
+CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *ctor,
+ const ConstantArrayType *arrayType,
+ llvm::Value *arrayBegin,
+ CallExpr::const_arg_iterator argBegin,
+ CallExpr::const_arg_iterator argEnd,
+ bool zeroInitialize) {
+ QualType elementType;
+ llvm::Value *numElements =
+ emitArrayLength(arrayType, elementType, arrayBegin);
+
+ EmitCXXAggrConstructorCall(ctor, numElements, arrayBegin,
+ argBegin, argEnd, zeroInitialize);
}
+/// EmitCXXAggrConstructorCall - Emit a loop to call a particular
+/// constructor for each of several members of an array.
+///
+/// \param ctor the constructor to call for each element
+/// \param numElements the number of elements in the array;
+/// may be zero
+/// \param argBegin,argEnd the arguments to evaluate and pass to the
+/// constructor
+/// \param arrayBegin a T*, where T is the type constructed by ctor
+/// \param zeroInitialize true if each element should be
+/// zero-initialized before it is constructed
void
-CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D,
- llvm::Value *NumElements,
- llvm::Value *ArrayPtr,
- CallExpr::const_arg_iterator ArgBeg,
- CallExpr::const_arg_iterator ArgEnd,
- bool ZeroInitialization) {
- const llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
-
- // Create a temporary for the loop index and initialize it with 0.
- llvm::Value *IndexPtr = CreateTempAlloca(SizeTy, "loop.index");
- llvm::Value *Zero = llvm::Constant::getNullValue(SizeTy);
- Builder.CreateStore(Zero, IndexPtr);
-
- // Start the loop with a block that tests the condition.
- llvm::BasicBlock *CondBlock = createBasicBlock("for.cond");
- llvm::BasicBlock *AfterFor = createBasicBlock("for.end");
-
- EmitBlock(CondBlock);
-
- llvm::BasicBlock *ForBody = createBasicBlock("for.body");
-
- // Generate: if (loop-index < number-of-elements fall to the loop body,
- // otherwise, go to the block after the for-loop.
- llvm::Value *Counter = Builder.CreateLoad(IndexPtr);
- llvm::Value *IsLess = Builder.CreateICmpULT(Counter, NumElements, "isless");
- // If the condition is true, execute the body.
- Builder.CreateCondBr(IsLess, ForBody, AfterFor);
-
- EmitBlock(ForBody);
+CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *ctor,
+ llvm::Value *numElements,
+ llvm::Value *arrayBegin,
+ CallExpr::const_arg_iterator argBegin,
+ CallExpr::const_arg_iterator argEnd,
+ bool zeroInitialize) {
+
+ // It's legal for numElements to be zero. This can happen both
+ // dynamically, because x can be zero in 'new A[x]', and statically,
+ // because of GCC extensions that permit zero-length arrays. There
+ // are probably legitimate places where we could assume that this
+ // doesn't happen, but it's not clear that it's worth it.
+ llvm::BranchInst *zeroCheckBranch = 0;
+
+ // Optimize for a constant count.
+ llvm::ConstantInt *constantCount
+ = dyn_cast<llvm::ConstantInt>(numElements);
+ if (constantCount) {
+ // Just skip out if the constant count is zero.
+ if (constantCount->isZero()) return;
+
+ // Otherwise, emit the check.
+ } else {
+ llvm::BasicBlock *loopBB = createBasicBlock("new.ctorloop");
+ llvm::Value *iszero = Builder.CreateIsNull(numElements, "isempty");
+ zeroCheckBranch = Builder.CreateCondBr(iszero, loopBB, loopBB);
+ EmitBlock(loopBB);
+ }
+
+ // Find the end of the array.
+ llvm::Value *arrayEnd = Builder.CreateInBoundsGEP(arrayBegin, numElements,
+ "arrayctor.end");
+
+ // Enter the loop, setting up a phi for the current location to initialize.
+ llvm::BasicBlock *entryBB = Builder.GetInsertBlock();
+ llvm::BasicBlock *loopBB = createBasicBlock("arrayctor.loop");
+ EmitBlock(loopBB);
+ llvm::PHINode *cur = Builder.CreatePHI(arrayBegin->getType(), 2,
+ "arrayctor.cur");
+ cur->addIncoming(arrayBegin, entryBB);
- llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc");
// Inside the loop body, emit the constructor call on the array element.
- Counter = Builder.CreateLoad(IndexPtr);
- llvm::Value *Address = Builder.CreateInBoundsGEP(ArrayPtr, Counter,
- "arrayidx");
+
+ QualType type = getContext().getTypeDeclType(ctor->getParent());
// Zero initialize the storage, if requested.
- if (ZeroInitialization)
- EmitNullInitialization(Address,
- getContext().getTypeDeclType(D->getParent()));
+ if (zeroInitialize)
+ EmitNullInitialization(cur, type);
// C++ [class.temporary]p4:
// There are two contexts in which temporaries are destroyed at a different
@@ -1134,99 +1127,47 @@ CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D,
// every temporary created in a default argument expression is sequenced
// before the construction of the next array element, if any.
- // Keep track of the current number of live temporaries.
{
RunCleanupsScope Scope(*this);
- EmitCXXConstructorCall(D, Ctor_Complete, /*ForVirtualBase=*/false, Address,
- ArgBeg, ArgEnd);
+ // Evaluate the constructor and its arguments in a regular
+ // partial-destroy cleanup.
+ if (getLangOptions().Exceptions &&
+ !ctor->getParent()->hasTrivialDestructor()) {
+ Destroyer *destroyer = destroyCXXObject;
+ pushRegularPartialArrayCleanup(arrayBegin, cur, type, *destroyer);
+ }
+
+ EmitCXXConstructorCall(ctor, Ctor_Complete, /*ForVirtualBase=*/ false,
+ cur, argBegin, argEnd);
}
- EmitBlock(ContinueBlock);
+ // Go to the next element.
+ llvm::Value *next =
+ Builder.CreateInBoundsGEP(cur, llvm::ConstantInt::get(SizeTy, 1),
+ "arrayctor.next");
+ cur->addIncoming(next, Builder.GetInsertBlock());
- // Emit the increment of the loop counter.
- llvm::Value *NextVal = llvm::ConstantInt::get(SizeTy, 1);
- Counter = Builder.CreateLoad(IndexPtr);
- NextVal = Builder.CreateAdd(Counter, NextVal, "inc");
- Builder.CreateStore(NextVal, IndexPtr);
+ // Check whether that's the end of the loop.
+ llvm::Value *done = Builder.CreateICmpEQ(next, arrayEnd, "arrayctor.done");
+ llvm::BasicBlock *contBB = createBasicBlock("arrayctor.cont");
+ Builder.CreateCondBr(done, contBB, loopBB);
- // Finally, branch back up to the condition for the next iteration.
- EmitBranch(CondBlock);
+ // Patch the earlier check to skip over the loop.
+ if (zeroCheckBranch) zeroCheckBranch->setSuccessor(0, contBB);
- // Emit the fall-through block.
- EmitBlock(AfterFor, true);
-}
-
-/// EmitCXXAggrDestructorCall - calls the default destructor on array
-/// elements in reverse order of construction.
-void
-CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D,
- const ArrayType *Array,
- llvm::Value *This) {
- const ConstantArrayType *CA = dyn_cast<ConstantArrayType>(Array);
- assert(CA && "Do we support VLA for destruction ?");
- uint64_t ElementCount = getContext().getConstantArrayElementCount(CA);
-
- const llvm::Type *SizeLTy = ConvertType(getContext().getSizeType());
- llvm::Value* ElementCountPtr = llvm::ConstantInt::get(SizeLTy, ElementCount);
- EmitCXXAggrDestructorCall(D, ElementCountPtr, This);
+ EmitBlock(contBB);
}
-/// EmitCXXAggrDestructorCall - calls the default destructor on array
-/// elements in reverse order of construction.
-void
-CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D,
- llvm::Value *UpperCount,
- llvm::Value *This) {
- const llvm::Type *SizeLTy = ConvertType(getContext().getSizeType());
- llvm::Value *One = llvm::ConstantInt::get(SizeLTy, 1);
-
- // Create a temporary for the loop index and initialize it with count of
- // array elements.
- llvm::Value *IndexPtr = CreateTempAlloca(SizeLTy, "loop.index");
-
- // Store the number of elements in the index pointer.
- Builder.CreateStore(UpperCount, IndexPtr);
-
- // Start the loop with a block that tests the condition.
- llvm::BasicBlock *CondBlock = createBasicBlock("for.cond");
- llvm::BasicBlock *AfterFor = createBasicBlock("for.end");
-
- EmitBlock(CondBlock);
-
- llvm::BasicBlock *ForBody = createBasicBlock("for.body");
-
- // Generate: if (loop-index != 0 fall to the loop body,
- // otherwise, go to the block after the for-loop.
- llvm::Value* zeroConstant =
- llvm::Constant::getNullValue(SizeLTy);
- llvm::Value *Counter = Builder.CreateLoad(IndexPtr);
- llvm::Value *IsNE = Builder.CreateICmpNE(Counter, zeroConstant,
- "isne");
- // If the condition is true, execute the body.
- Builder.CreateCondBr(IsNE, ForBody, AfterFor);
-
- EmitBlock(ForBody);
-
- llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc");
- // Inside the loop body, emit the constructor call on the array element.
- Counter = Builder.CreateLoad(IndexPtr);
- Counter = Builder.CreateSub(Counter, One);
- llvm::Value *Address = Builder.CreateInBoundsGEP(This, Counter, "arrayidx");
- EmitCXXDestructorCall(D, Dtor_Complete, /*ForVirtualBase=*/false, Address);
-
- EmitBlock(ContinueBlock);
-
- // Emit the decrement of the loop counter.
- Counter = Builder.CreateLoad(IndexPtr);
- Counter = Builder.CreateSub(Counter, One, "dec");
- Builder.CreateStore(Counter, IndexPtr);
-
- // Finally, branch back up to the condition for the next iteration.
- EmitBranch(CondBlock);
-
- // Emit the fall-through block.
- EmitBlock(AfterFor, true);
+void CodeGenFunction::destroyCXXObject(CodeGenFunction &CGF,
+ llvm::Value *addr,
+ QualType type) {
+ const RecordType *rtype = type->castAs<RecordType>();
+ const CXXRecordDecl *record = cast<CXXRecordDecl>(rtype->getDecl());
+ const CXXDestructorDecl *dtor = record->getDestructor();
+ assert(!dtor->isTrivial());
+ CGF.EmitCXXDestructorCall(dtor, Dtor_Complete, /*for vbase*/ false,
+ addr);
}
void
@@ -1370,7 +1311,7 @@ namespace {
CXXDtorType Type)
: Dtor(D), Addr(Addr), Type(Type) {}
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
CGF.EmitCXXDestructorCall(Dtor, Type, /*ForVirtualBase=*/false,
Addr);
}
@@ -1384,7 +1325,8 @@ CodeGenFunction::EmitDelegatingCXXConstructorCall(const CXXConstructorDecl *Ctor
llvm::Value *ThisPtr = LoadCXXThis();
- AggValueSlot AggSlot = AggValueSlot::forAddr(ThisPtr, false, /*Lifetime*/ true);
+ AggValueSlot AggSlot =
+ AggValueSlot::forAddr(ThisPtr, Qualifiers(), /*Lifetime*/ true);
EmitAggExpr(Ctor->init_begin()[0]->getInit(), AggSlot);
@@ -1424,7 +1366,7 @@ namespace {
CallLocalDtor(const CXXDestructorDecl *D, llvm::Value *Addr)
: Dtor(D), Addr(Addr) {}
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete,
/*ForVirtualBase=*/false, Addr);
}
diff --git a/lib/CodeGen/CGCleanup.cpp b/lib/CodeGen/CGCleanup.cpp
index 41ecd8111790..9c5dd1f23721 100644
--- a/lib/CodeGen/CGCleanup.cpp
+++ b/lib/CodeGen/CGCleanup.cpp
@@ -49,8 +49,7 @@ DominatingValue<RValue>::saved_type::save(CodeGenFunction &CGF, RValue rv) {
if (rv.isComplex()) {
CodeGenFunction::ComplexPairTy V = rv.getComplexVal();
const llvm::Type *ComplexTy =
- llvm::StructType::get(CGF.getLLVMContext(),
- V.first->getType(), V.second->getType(),
+ llvm::StructType::get(V.first->getType(), V.second->getType(),
(void*) 0);
llvm::Value *addr = CGF.CreateTempAlloca(ComplexTy, "saved-complex");
CGF.StoreComplexToAddr(V, addr, /*volatile*/ false);
@@ -257,9 +256,7 @@ void CodeGenFunction::initFullExprCleanup() {
if (cleanup.isEHCleanup()) cleanup.setTestFlagInEHCleanup();
}
-EHScopeStack::Cleanup::~Cleanup() {
- llvm_unreachable("Cleanup is indestructable");
-}
+void EHScopeStack::Cleanup::anchor() {}
/// All the branch fixups on the EH stack have propagated out past the
/// outermost normal cleanup; resolve them all by adding cases to the
@@ -421,13 +418,13 @@ static llvm::BasicBlock *SimplifyCleanupEntry(CodeGenFunction &CGF,
// Kill the branch.
Br->eraseFromParent();
- // Merge the blocks.
- Pred->getInstList().splice(Pred->end(), Entry->getInstList());
-
// Replace all uses of the entry with the predecessor, in case there
// are phis in the cleanup.
Entry->replaceAllUsesWith(Pred);
+ // Merge the blocks.
+ Pred->getInstList().splice(Pred->end(), Entry->getInstList());
+
// Kill the entry block.
Entry->eraseFromParent();
@@ -439,10 +436,10 @@ static llvm::BasicBlock *SimplifyCleanupEntry(CodeGenFunction &CGF,
static void EmitCleanup(CodeGenFunction &CGF,
EHScopeStack::Cleanup *Fn,
- bool ForEH,
+ EHScopeStack::Cleanup::Flags flags,
llvm::Value *ActiveFlag) {
// EH cleanups always occur within a terminate scope.
- if (ForEH) CGF.EHStack.pushTerminate();
+ if (flags.isForEHCleanup()) CGF.EHStack.pushTerminate();
// If there's an active flag, load it and skip the cleanup if it's
// false.
@@ -457,7 +454,7 @@ static void EmitCleanup(CodeGenFunction &CGF,
}
// Ask the cleanup to emit itself.
- Fn->Emit(CGF, ForEH);
+ Fn->Emit(CGF, flags);
assert(CGF.HaveInsertPoint() && "cleanup ended with no insertion point?");
// Emit the continuation block if there was an active flag.
@@ -465,7 +462,7 @@ static void EmitCleanup(CodeGenFunction &CGF,
CGF.EmitBlock(ContBB);
// Leave the terminate scope.
- if (ForEH) CGF.EHStack.popTerminate();
+ if (flags.isForEHCleanup()) CGF.EHStack.popTerminate();
}
static void ForwardPrebranchedFallthrough(llvm::BasicBlock *Exit,
@@ -540,6 +537,12 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
RequiresNormalCleanup = true;
}
+ EHScopeStack::Cleanup::Flags cleanupFlags;
+ if (Scope.isNormalCleanup())
+ cleanupFlags.setIsNormalCleanupKind();
+ if (Scope.isEHCleanup())
+ cleanupFlags.setIsEHCleanupKind();
+
// Even if we don't need the normal cleanup, we might still have
// prebranched fallthrough to worry about.
if (Scope.isNormalCleanup() && !RequiresNormalCleanup &&
@@ -663,7 +666,7 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
EHStack.popCleanup();
- EmitCleanup(*this, Fn, /*ForEH*/ false, NormalActiveFlag);
+ EmitCleanup(*this, Fn, cleanupFlags, NormalActiveFlag);
// Otherwise, the best approach is to thread everything through
// the cleanup block and then try to clean up after ourselves.
@@ -774,7 +777,7 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
EHStack.popCleanup();
assert(EHStack.hasNormalCleanups() == HasEnclosingCleanups);
- EmitCleanup(*this, Fn, /*ForEH*/ false, NormalActiveFlag);
+ EmitCleanup(*this, Fn, cleanupFlags, NormalActiveFlag);
// Append the prepared cleanup prologue from above.
llvm::BasicBlock *NormalExit = Builder.GetInsertBlock();
@@ -857,7 +860,9 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP();
EmitBlock(EHEntry);
- EmitCleanup(*this, Fn, /*ForEH*/ true, EHActiveFlag);
+
+ cleanupFlags.setIsForEHCleanup();
+ EmitCleanup(*this, Fn, cleanupFlags, EHActiveFlag);
// Append the prepared cleanup prologue from above.
llvm::BasicBlock *EHExit = Builder.GetInsertBlock();
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index 98d30db647d5..4c1244591743 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -314,8 +314,9 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) {
llvm::SmallVector<llvm::Value *, 16> EltTys;
llvm::DIType FieldTy =
- DBuilder.createMemberType("isa", getOrCreateMainFile(),
- 0,Size, 0, 0, 0, ISATy);
+ DBuilder.createMemberType(getOrCreateMainFile(), "isa",
+ getOrCreateMainFile(), 0, Size,
+ 0, 0, 0, ISATy);
EltTys.push_back(FieldTy);
llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys);
@@ -389,6 +390,7 @@ llvm::DIType CGDebugInfo::CreateQualifiedType(QualType Ty, llvm::DIFile Unit) {
// Ignore these qualifiers for now.
Qc.removeObjCGCAttr();
Qc.removeAddressSpace();
+ Qc.removeObjCLifetime();
// We will create one Derived type for one qualifier and recurse to handle any
// additional ones.
@@ -528,7 +530,7 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
FieldTy = DescTy;
FieldSize = CGM.getContext().getTypeSize(Ty);
FieldAlign = CGM.getContext().getTypeAlign(Ty);
- FieldTy = DBuilder.createMemberType("__descriptor", Unit,
+ FieldTy = DBuilder.createMemberType(Unit, "__descriptor", Unit,
LineNo, FieldSize, FieldAlign,
FieldOffset, 0, FieldTy);
EltTys.push_back(FieldTy);
@@ -591,7 +593,8 @@ llvm::DIType CGDebugInfo::createFieldType(llvm::StringRef name,
SourceLocation loc,
AccessSpecifier AS,
uint64_t offsetInBits,
- llvm::DIFile tunit) {
+ llvm::DIFile tunit,
+ llvm::DIDescriptor scope) {
llvm::DIType debugType = getOrCreateType(type, tunit);
// Get the location for the field.
@@ -613,15 +616,16 @@ llvm::DIType CGDebugInfo::createFieldType(llvm::StringRef name,
else if (AS == clang::AS_protected)
flags |= llvm::DIDescriptor::FlagProtected;
- return DBuilder.createMemberType(name, file, line, sizeInBits, alignInBits,
- offsetInBits, flags, debugType);
+ return DBuilder.createMemberType(scope, name, file, line, sizeInBits,
+ alignInBits, offsetInBits, flags, debugType);
}
/// CollectRecordFields - A helper function to collect debug info for
/// record fields. This is used while creating debug info entry for a Record.
void CGDebugInfo::
CollectRecordFields(const RecordDecl *record, llvm::DIFile tunit,
- llvm::SmallVectorImpl<llvm::Value *> &elements) {
+ llvm::SmallVectorImpl<llvm::Value *> &elements,
+ llvm::DIType RecordTy) {
unsigned fieldNo = 0;
const FieldDecl *LastFD = 0;
bool IsMsStruct = record->hasAttr<MsStructAttr>();
@@ -652,7 +656,7 @@ CollectRecordFields(const RecordDecl *record, llvm::DIFile tunit,
llvm::DIType fieldType
= createFieldType(name, type, field->getBitWidth(),
field->getLocation(), field->getAccess(),
- layout.getFieldOffset(fieldNo), tunit);
+ layout.getFieldOffset(fieldNo), tunit, RecordTy);
elements.push_back(fieldType);
}
@@ -960,7 +964,7 @@ CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile Unit,
unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy);
llvm::DIType VPTR
- = DBuilder.createMemberType(getVTableName(RD), Unit,
+ = DBuilder.createMemberType(Unit, getVTableName(RD), Unit,
0, Size, 0, 0, 0,
getOrCreateVTablePtrType(Unit));
EltTys.push_back(VPTR);
@@ -1048,7 +1052,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) {
}
}
- CollectRecordFields(RD, Unit, EltTys);
+ CollectRecordFields(RD, Unit, EltTys, FwdDecl);
llvm::DIArray TParamsArray;
if (CXXDecl) {
CollectCXXMemberFunctions(CXXDecl, Unit, EltTys, FwdDecl);
@@ -1379,13 +1383,13 @@ llvm::DIType CGDebugInfo::CreateType(const MemberPointerType *Ty,
// FIXME: This should probably be a function type instead.
ElementTypes[0] =
- DBuilder.createMemberType("ptr", U, 0,
+ DBuilder.createMemberType(U, "ptr", U, 0,
Info.first, Info.second, FieldOffset, 0,
PointerDiffDITy);
FieldOffset += Info.first;
ElementTypes[1] =
- DBuilder.createMemberType("ptr", U, 0,
+ DBuilder.createMemberType(U, "ptr", U, 0,
Info.first, Info.second, FieldOffset, 0,
PointerDiffDITy);
@@ -1520,10 +1524,7 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty,
#include "clang/AST/TypeNodes.def"
assert(false && "Dependent types cannot show up in debug information");
- // FIXME: Handle these.
case Type::ExtVector:
- return llvm::DIType();
-
case Type::Vector:
return CreateType(cast<VectorType>(Ty), Unit);
case Type::ObjCObjectPointer:
@@ -1586,7 +1587,7 @@ llvm::DIType CGDebugInfo::CreateMemberType(llvm::DIFile Unit, QualType FType,
llvm::DIType FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
uint64_t FieldSize = CGM.getContext().getTypeSize(FType);
unsigned FieldAlign = CGM.getContext().getTypeAlign(FType);
- llvm::DIType Ty = DBuilder.createMemberType(Name, Unit, 0,
+ llvm::DIType Ty = DBuilder.createMemberType(Unit, Name, Unit, 0,
FieldSize, FieldAlign,
*Offset, 0, FieldTy);
*Offset += FieldSize;
@@ -1897,7 +1898,7 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD,
FieldAlign = CGM.getContext().toBits(Align);
*XOffset = FieldOffset;
- FieldTy = DBuilder.createMemberType(VD->getName(), Unit,
+ FieldTy = DBuilder.createMemberType(Unit, VD->getName(), Unit,
0, FieldSize, FieldAlign,
FieldOffset, 0, FieldTy);
EltTys.push_back(FieldTy);
@@ -2133,23 +2134,23 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
llvm::SmallVector<llvm::Value*, 16> fields;
fields.push_back(createFieldType("__isa", C.VoidPtrTy, 0, loc, AS_public,
blockLayout->getElementOffsetInBits(0),
- tunit));
+ tunit, tunit));
fields.push_back(createFieldType("__flags", C.IntTy, 0, loc, AS_public,
blockLayout->getElementOffsetInBits(1),
- tunit));
+ tunit, tunit));
fields.push_back(createFieldType("__reserved", C.IntTy, 0, loc, AS_public,
blockLayout->getElementOffsetInBits(2),
- tunit));
+ tunit, tunit));
fields.push_back(createFieldType("__FuncPtr", C.VoidPtrTy, 0, loc, AS_public,
blockLayout->getElementOffsetInBits(3),
- tunit));
+ tunit, tunit));
fields.push_back(createFieldType("__descriptor",
C.getPointerType(block.NeedsCopyDispose ?
C.getBlockDescriptorExtendedType() :
C.getBlockDescriptorType()),
0, loc, AS_public,
blockLayout->getElementOffsetInBits(4),
- tunit));
+ tunit, tunit));
// We want to sort the captures by offset, not because DWARF
// requires this, but because we're paranoid about debuggers.
@@ -2198,7 +2199,7 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
QualType type = method->getThisType(C);
fields.push_back(createFieldType("this", type, 0, loc, AS_public,
- offsetInBits, tunit));
+ offsetInBits, tunit, tunit));
continue;
}
@@ -2213,12 +2214,12 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
uint64_t xoffset;
fieldType = EmitTypeForVarWithBlocksAttr(variable, &xoffset);
fieldType = DBuilder.createPointerType(fieldType, ptrInfo.first);
- fieldType = DBuilder.createMemberType(name, tunit, line,
+ fieldType = DBuilder.createMemberType(tunit, name, tunit, line,
ptrInfo.first, ptrInfo.second,
offsetInBits, 0, fieldType);
} else {
fieldType = createFieldType(name, variable->getType(), 0,
- loc, AS_public, offsetInBits, tunit);
+ loc, AS_public, offsetInBits, tunit, tunit);
}
fields.push_back(fieldType);
}
diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h
index 6ec6b65f5e01..f87d0072e323 100644
--- a/lib/CodeGen/CGDebugInfo.h
+++ b/lib/CodeGen/CGDebugInfo.h
@@ -33,11 +33,11 @@ namespace clang {
class VarDecl;
class ObjCInterfaceDecl;
class ClassTemplateSpecializationDecl;
+ class GlobalDecl;
namespace CodeGen {
class CodeGenModule;
class CodeGenFunction;
- class GlobalDecl;
class CGBlockInfo;
/// CGDebugInfo - This class gathers all debug information during compilation
@@ -139,9 +139,11 @@ class CGDebugInfo {
llvm::DIType createFieldType(llvm::StringRef name, QualType type,
Expr *bitWidth, SourceLocation loc,
AccessSpecifier AS, uint64_t offsetInBits,
- llvm::DIFile tunit);
+ llvm::DIFile tunit,
+ llvm::DIDescriptor scope);
void CollectRecordFields(const RecordDecl *Decl, llvm::DIFile F,
- llvm::SmallVectorImpl<llvm::Value *> &E);
+ llvm::SmallVectorImpl<llvm::Value *> &E,
+ llvm::DIType RecordTy);
void CollectVTableInfo(const CXXRecordDecl *Decl,
llvm::DIFile F,
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 8a1a8536dab1..62c3a9791d0f 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -98,7 +98,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
QualType Ty = TD.getUnderlyingType();
if (Ty->isVariablyModifiedType())
- EmitVLASize(Ty);
+ EmitVariablyModifiedType(Ty);
}
}
}
@@ -258,7 +258,7 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D,
// even though that doesn't really make any sense.
// Make sure to evaluate VLA bounds now so that we have them for later.
if (D.getType()->isVariablyModifiedType())
- EmitVLASize(D.getType());
+ EmitVariablyModifiedType(D.getType());
// Local static block variables must be treated as globals as they may be
// referenced in their RHS initializer block-literal expresion.
@@ -304,38 +304,40 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D,
}
namespace {
- struct CallArrayDtor : EHScopeStack::Cleanup {
- CallArrayDtor(const CXXDestructorDecl *Dtor,
- const ConstantArrayType *Type,
- llvm::Value *Loc)
- : Dtor(Dtor), Type(Type), Loc(Loc) {}
-
- const CXXDestructorDecl *Dtor;
- const ConstantArrayType *Type;
- llvm::Value *Loc;
-
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
- QualType BaseElementTy = CGF.getContext().getBaseElementType(Type);
- const llvm::Type *BasePtr = CGF.ConvertType(BaseElementTy);
- BasePtr = llvm::PointerType::getUnqual(BasePtr);
- llvm::Value *BaseAddrPtr = CGF.Builder.CreateBitCast(Loc, BasePtr);
- CGF.EmitCXXAggrDestructorCall(Dtor, Type, BaseAddrPtr);
+ struct DestroyObject : EHScopeStack::Cleanup {
+ DestroyObject(llvm::Value *addr, QualType type,
+ CodeGenFunction::Destroyer *destroyer,
+ bool useEHCleanupForArray)
+ : addr(addr), type(type), destroyer(*destroyer),
+ useEHCleanupForArray(useEHCleanupForArray) {}
+
+ llvm::Value *addr;
+ QualType type;
+ CodeGenFunction::Destroyer &destroyer;
+ bool useEHCleanupForArray;
+
+ void Emit(CodeGenFunction &CGF, Flags flags) {
+ // Don't use an EH cleanup recursively from an EH cleanup.
+ bool useEHCleanupForArray =
+ flags.isForNormalCleanup() && this->useEHCleanupForArray;
+
+ CGF.emitDestroy(addr, type, destroyer, useEHCleanupForArray);
}
};
- struct CallVarDtor : EHScopeStack::Cleanup {
- CallVarDtor(const CXXDestructorDecl *Dtor,
- llvm::Value *NRVOFlag,
- llvm::Value *Loc)
- : Dtor(Dtor), NRVOFlag(NRVOFlag), Loc(Loc) {}
+ struct DestroyNRVOVariable : EHScopeStack::Cleanup {
+ DestroyNRVOVariable(llvm::Value *addr,
+ const CXXDestructorDecl *Dtor,
+ llvm::Value *NRVOFlag)
+ : Dtor(Dtor), NRVOFlag(NRVOFlag), Loc(addr) {}
const CXXDestructorDecl *Dtor;
llvm::Value *NRVOFlag;
llvm::Value *Loc;
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
// Along the exceptions path we always execute the dtor.
- bool NRVO = !IsForEH && NRVOFlag;
+ bool NRVO = flags.isForNormalCleanup() && NRVOFlag;
llvm::BasicBlock *SkipDtorBB = 0;
if (NRVO) {
@@ -353,19 +355,31 @@ namespace {
if (NRVO) CGF.EmitBlock(SkipDtorBB);
}
};
-}
-namespace {
struct CallStackRestore : EHScopeStack::Cleanup {
llvm::Value *Stack;
CallStackRestore(llvm::Value *Stack) : Stack(Stack) {}
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
llvm::Value *V = CGF.Builder.CreateLoad(Stack, "tmp");
llvm::Value *F = CGF.CGM.getIntrinsic(llvm::Intrinsic::stackrestore);
CGF.Builder.CreateCall(F, V);
}
};
+ struct ExtendGCLifetime : EHScopeStack::Cleanup {
+ const VarDecl &Var;
+ ExtendGCLifetime(const VarDecl *var) : Var(*var) {}
+
+ void Emit(CodeGenFunction &CGF, Flags flags) {
+ // Compute the address of the local variable, in case it's a
+ // byref or something.
+ DeclRefExpr DRE(const_cast<VarDecl*>(&Var), Var.getType(), VK_LValue,
+ SourceLocation());
+ llvm::Value *value = CGF.EmitLoadOfScalar(CGF.EmitDeclRefLValue(&DRE));
+ CGF.EmitExtendGCLifetime(value);
+ }
+ };
+
struct CallCleanupFunction : EHScopeStack::Cleanup {
llvm::Constant *CleanupFn;
const CGFunctionInfo &FnInfo;
@@ -375,7 +389,7 @@ namespace {
const VarDecl *Var)
: CleanupFn(CleanupFn), FnInfo(*Info), Var(*Var) {}
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
DeclRefExpr DRE(const_cast<VarDecl*>(&Var), Var.getType(), VK_LValue,
SourceLocation());
// Compute the address of the local variable, in case it's a byref
@@ -400,6 +414,207 @@ namespace {
};
}
+/// EmitAutoVarWithLifetime - Does the setup required for an automatic
+/// variable with lifetime.
+static void EmitAutoVarWithLifetime(CodeGenFunction &CGF, const VarDecl &var,
+ llvm::Value *addr,
+ Qualifiers::ObjCLifetime lifetime) {
+ switch (lifetime) {
+ case Qualifiers::OCL_None:
+ llvm_unreachable("present but none");
+
+ case Qualifiers::OCL_ExplicitNone:
+ // nothing to do
+ break;
+
+ case Qualifiers::OCL_Strong: {
+ CodeGenFunction::Destroyer &destroyer =
+ (var.hasAttr<ObjCPreciseLifetimeAttr>()
+ ? CodeGenFunction::destroyARCStrongPrecise
+ : CodeGenFunction::destroyARCStrongImprecise);
+
+ CleanupKind cleanupKind = CGF.getARCCleanupKind();
+ CGF.pushDestroy(cleanupKind, addr, var.getType(), destroyer,
+ cleanupKind & EHCleanup);
+ break;
+ }
+ case Qualifiers::OCL_Autoreleasing:
+ // nothing to do
+ break;
+
+ case Qualifiers::OCL_Weak:
+ // __weak objects always get EH cleanups; otherwise, exceptions
+ // could cause really nasty crashes instead of mere leaks.
+ CGF.pushDestroy(NormalAndEHCleanup, addr, var.getType(),
+ CodeGenFunction::destroyARCWeak,
+ /*useEHCleanup*/ true);
+ break;
+ }
+}
+
+static bool isAccessedBy(const VarDecl &var, const Stmt *s) {
+ if (const Expr *e = dyn_cast<Expr>(s)) {
+ // Skip the most common kinds of expressions that make
+ // hierarchy-walking expensive.
+ s = e = e->IgnoreParenCasts();
+
+ if (const DeclRefExpr *ref = dyn_cast<DeclRefExpr>(e))
+ return (ref->getDecl() == &var);
+ }
+
+ for (Stmt::const_child_range children = s->children(); children; ++children)
+ // children might be null; as in missing decl or conditional of an if-stmt.
+ if ((*children) && isAccessedBy(var, *children))
+ return true;
+
+ return false;
+}
+
+static bool isAccessedBy(const ValueDecl *decl, const Expr *e) {
+ if (!decl) return false;
+ if (!isa<VarDecl>(decl)) return false;
+ const VarDecl *var = cast<VarDecl>(decl);
+ return isAccessedBy(*var, e);
+}
+
+static void drillIntoBlockVariable(CodeGenFunction &CGF,
+ LValue &lvalue,
+ const VarDecl *var) {
+ lvalue.setAddress(CGF.BuildBlockByrefAddress(lvalue.getAddress(), var));
+}
+
+void CodeGenFunction::EmitScalarInit(const Expr *init,
+ const ValueDecl *D,
+ LValue lvalue,
+ bool capturedByInit) {
+ Qualifiers::ObjCLifetime lifetime = lvalue.getObjCLifetime();
+ if (!lifetime) {
+ llvm::Value *value = EmitScalarExpr(init);
+ if (capturedByInit)
+ drillIntoBlockVariable(*this, lvalue, cast<VarDecl>(D));
+ EmitStoreThroughLValue(RValue::get(value), lvalue);
+ return;
+ }
+
+ // If we're emitting a value with lifetime, we have to do the
+ // initialization *before* we leave the cleanup scopes.
+ CodeGenFunction::RunCleanupsScope Scope(*this);
+ if (const ExprWithCleanups *ewc = dyn_cast<ExprWithCleanups>(init))
+ init = ewc->getSubExpr();
+
+ // We have to maintain the illusion that the variable is
+ // zero-initialized. If the variable might be accessed in its
+ // initializer, zero-initialize before running the initializer, then
+ // actually perform the initialization with an assign.
+ bool accessedByInit = false;
+ if (lifetime != Qualifiers::OCL_ExplicitNone)
+ accessedByInit = isAccessedBy(D, init);
+ if (accessedByInit) {
+ LValue tempLV = lvalue;
+ // Drill down to the __block object if necessary.
+ if (capturedByInit) {
+ // We can use a simple GEP for this because it can't have been
+ // moved yet.
+ tempLV.setAddress(Builder.CreateStructGEP(tempLV.getAddress(),
+ getByRefValueLLVMField(cast<VarDecl>(D))));
+ }
+
+ const llvm::PointerType *ty
+ = cast<llvm::PointerType>(tempLV.getAddress()->getType());
+ ty = cast<llvm::PointerType>(ty->getElementType());
+
+ llvm::Value *zero = llvm::ConstantPointerNull::get(ty);
+
+ // If __weak, we want to use a barrier under certain conditions.
+ if (lifetime == Qualifiers::OCL_Weak)
+ EmitARCInitWeak(tempLV.getAddress(), zero);
+
+ // Otherwise just do a simple store.
+ else
+ EmitStoreOfScalar(zero, tempLV);
+ }
+
+ // Emit the initializer.
+ llvm::Value *value = 0;
+
+ switch (lifetime) {
+ case Qualifiers::OCL_None:
+ llvm_unreachable("present but none");
+
+ case Qualifiers::OCL_ExplicitNone:
+ // nothing to do
+ value = EmitScalarExpr(init);
+ break;
+
+ case Qualifiers::OCL_Strong: {
+ value = EmitARCRetainScalarExpr(init);
+ break;
+ }
+
+ case Qualifiers::OCL_Weak: {
+ // No way to optimize a producing initializer into this. It's not
+ // worth optimizing for, because the value will immediately
+ // disappear in the common case.
+ value = EmitScalarExpr(init);
+
+ if (capturedByInit) drillIntoBlockVariable(*this, lvalue, cast<VarDecl>(D));
+ if (accessedByInit)
+ EmitARCStoreWeak(lvalue.getAddress(), value, /*ignored*/ true);
+ else
+ EmitARCInitWeak(lvalue.getAddress(), value);
+ return;
+ }
+
+ case Qualifiers::OCL_Autoreleasing:
+ value = EmitARCRetainAutoreleaseScalarExpr(init);
+ break;
+ }
+
+ if (capturedByInit) drillIntoBlockVariable(*this, lvalue, cast<VarDecl>(D));
+
+ // If the variable might have been accessed by its initializer, we
+ // might have to initialize with a barrier. We have to do this for
+ // both __weak and __strong, but __weak got filtered out above.
+ if (accessedByInit && lifetime == Qualifiers::OCL_Strong) {
+ llvm::Value *oldValue = EmitLoadOfScalar(lvalue);
+ EmitStoreOfScalar(value, lvalue);
+ EmitARCRelease(oldValue, /*precise*/ false);
+ return;
+ }
+
+ EmitStoreOfScalar(value, lvalue);
+}
+
+/// EmitScalarInit - Initialize the given lvalue with the given object.
+void CodeGenFunction::EmitScalarInit(llvm::Value *init, LValue lvalue) {
+ Qualifiers::ObjCLifetime lifetime = lvalue.getObjCLifetime();
+ if (!lifetime)
+ return EmitStoreThroughLValue(RValue::get(init), lvalue);
+
+ switch (lifetime) {
+ case Qualifiers::OCL_None:
+ llvm_unreachable("present but none");
+
+ case Qualifiers::OCL_ExplicitNone:
+ // nothing to do
+ break;
+
+ case Qualifiers::OCL_Strong:
+ init = EmitARCRetain(lvalue.getType(), init);
+ break;
+
+ case Qualifiers::OCL_Weak:
+ // Initialize and then skip the primitive store.
+ EmitARCInitWeak(lvalue.getAddress(), init);
+ return;
+
+ case Qualifiers::OCL_Autoreleasing:
+ init = EmitARCRetainAutorelease(lvalue.getType(), init);
+ break;
+ }
+
+ EmitStoreOfScalar(init, lvalue);
+}
/// canEmitInitWithFewStoresAfterMemset - Decide whether we can emit the
/// non-zero parts of the specified initializer with equal or fewer than
@@ -508,6 +723,10 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
CharUnits alignment = getContext().getDeclAlign(&D);
emission.Alignment = alignment;
+ // If the type is variably-modified, emit all the VLA sizes for it.
+ if (Ty->isVariablyModifiedType())
+ EmitVariablyModifiedType(Ty);
+
llvm::Value *DeclPtr;
if (Ty->isConstantSizeType()) {
if (!Target.useGlobalsForAutomaticVariables()) {
@@ -521,7 +740,9 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
// arrays as long as the initialization is trivial (e.g. if they
// have a non-trivial destructor, but not a non-trivial constructor).
if (D.getInit() &&
- (Ty->isArrayType() || Ty->isRecordType()) && Ty->isPODType() &&
+ (Ty->isArrayType() || Ty->isRecordType()) &&
+ (Ty.isPODType(getContext()) ||
+ getContext().getBaseElementType(Ty)->isObjCObjectPointerType()) &&
D.getInit()->isConstantInitializer(getContext(), false)) {
// If the variable's a const type, and it's neither an NRVO
@@ -585,10 +806,6 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
DeclPtr = CreateStaticVarDecl(D, Class,
llvm::GlobalValue::InternalLinkage);
}
-
- // FIXME: Can this happen?
- if (Ty->isVariablyModifiedType())
- EmitVLASize(Ty);
} else {
EnsureInsertPoint();
@@ -608,19 +825,17 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
EHStack.pushCleanup<CallStackRestore>(NormalCleanup, Stack);
}
- // Get the element type.
- const llvm::Type *LElemTy = ConvertTypeForMem(Ty);
- const llvm::Type *LElemPtrTy =
- LElemTy->getPointerTo(CGM.getContext().getTargetAddressSpace(Ty));
+ llvm::Value *elementCount;
+ QualType elementType;
+ llvm::tie(elementCount, elementType) = getVLASize(Ty);
- llvm::Value *VLASize = EmitVLASize(Ty);
+ const llvm::Type *llvmTy = ConvertTypeForMem(elementType);
// Allocate memory for the array.
- llvm::AllocaInst *VLA =
- Builder.CreateAlloca(llvm::Type::getInt8Ty(getLLVMContext()), VLASize, "vla");
- VLA->setAlignment(alignment.getQuantity());
+ llvm::AllocaInst *vla = Builder.CreateAlloca(llvmTy, elementCount, "vla");
+ vla->setAlignment(alignment.getQuantity());
- DeclPtr = Builder.CreateBitCast(VLA, LElemPtrTy, "tmp");
+ DeclPtr = vla;
}
llvm::Value *&DMEntry = LocalDeclMap[&D];
@@ -667,6 +882,21 @@ static bool isCapturedBy(const VarDecl &var, const Expr *e) {
return false;
}
+/// \brief Determine whether the given initializer is trivial in the sense
+/// that it requires no code to be generated.
+static bool isTrivialInitializer(const Expr *Init) {
+ if (!Init)
+ return true;
+
+ if (const CXXConstructExpr *Construct = dyn_cast<CXXConstructExpr>(Init))
+ if (CXXConstructorDecl *Constructor = Construct->getConstructor())
+ if (Constructor->isTrivial() &&
+ Constructor->isDefaultConstructor() &&
+ !Construct->requiresZeroInitialization())
+ return true;
+
+ return false;
+}
void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
assert(emission.Variable && "emission was not valid!");
@@ -690,7 +920,9 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
if (emission.IsByRef)
emitByrefStructureInit(emission);
- if (!Init) return;
+ if (isTrivialInitializer(Init))
+ return;
+
CharUnits alignment = emission.Alignment;
@@ -702,8 +934,11 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
llvm::Value *Loc =
capturedByInit ? emission.Address : emission.getObjectAddress(*this);
- if (!emission.IsConstantAggregate)
- return EmitExprAsInit(Init, &D, Loc, alignment, capturedByInit);
+ if (!emission.IsConstantAggregate) {
+ LValue lv = MakeAddrLValue(Loc, type, alignment.getQuantity());
+ lv.setNonGC(true);
+ return EmitExprAsInit(Init, &D, lv, capturedByInit);
+ }
// If this is a simple aggregate initialization, we can optimize it
// in various ways.
@@ -765,32 +1000,87 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
/// \param capturedByInit true if the variable is a __block variable
/// whose address is potentially changed by the initializer
void CodeGenFunction::EmitExprAsInit(const Expr *init,
- const VarDecl *var,
- llvm::Value *loc,
- CharUnits alignment,
+ const ValueDecl *D,
+ LValue lvalue,
bool capturedByInit) {
- QualType type = var->getType();
- bool isVolatile = type.isVolatileQualified();
+ QualType type = D->getType();
if (type->isReferenceType()) {
- RValue RV = EmitReferenceBindingToExpr(init, var);
- if (capturedByInit) loc = BuildBlockByrefAddress(loc, var);
- EmitStoreOfScalar(RV.getScalarVal(), loc, false,
- alignment.getQuantity(), type);
+ RValue rvalue = EmitReferenceBindingToExpr(init, D);
+ if (capturedByInit)
+ drillIntoBlockVariable(*this, lvalue, cast<VarDecl>(D));
+ EmitStoreThroughLValue(rvalue, lvalue);
} else if (!hasAggregateLLVMType(type)) {
- llvm::Value *V = EmitScalarExpr(init);
- if (capturedByInit) loc = BuildBlockByrefAddress(loc, var);
- EmitStoreOfScalar(V, loc, isVolatile, alignment.getQuantity(), type);
+ EmitScalarInit(init, D, lvalue, capturedByInit);
} else if (type->isAnyComplexType()) {
ComplexPairTy complex = EmitComplexExpr(init);
- if (capturedByInit) loc = BuildBlockByrefAddress(loc, var);
- StoreComplexToAddr(complex, loc, isVolatile);
+ if (capturedByInit)
+ drillIntoBlockVariable(*this, lvalue, cast<VarDecl>(D));
+ StoreComplexToAddr(complex, lvalue.getAddress(), lvalue.isVolatile());
} else {
// TODO: how can we delay here if D is captured by its initializer?
- EmitAggExpr(init, AggValueSlot::forAddr(loc, isVolatile, true, false));
+ EmitAggExpr(init, AggValueSlot::forLValue(lvalue, true, false));
}
}
+/// Enter a destroy cleanup for the given local variable.
+void CodeGenFunction::emitAutoVarTypeCleanup(
+ const CodeGenFunction::AutoVarEmission &emission,
+ QualType::DestructionKind dtorKind) {
+ assert(dtorKind != QualType::DK_none);
+
+ // Note that for __block variables, we want to destroy the
+ // original stack object, not the possibly forwarded object.
+ llvm::Value *addr = emission.getObjectAddress(*this);
+
+ const VarDecl *var = emission.Variable;
+ QualType type = var->getType();
+
+ CleanupKind cleanupKind = NormalAndEHCleanup;
+ CodeGenFunction::Destroyer *destroyer = 0;
+
+ switch (dtorKind) {
+ case QualType::DK_none:
+ llvm_unreachable("no cleanup for trivially-destructible variable");
+
+ case QualType::DK_cxx_destructor:
+ // If there's an NRVO flag on the emission, we need a different
+ // cleanup.
+ if (emission.NRVOFlag) {
+ assert(!type->isArrayType());
+ CXXDestructorDecl *dtor = type->getAsCXXRecordDecl()->getDestructor();
+ EHStack.pushCleanup<DestroyNRVOVariable>(cleanupKind, addr, dtor,
+ emission.NRVOFlag);
+ return;
+ }
+ break;
+
+ case QualType::DK_objc_strong_lifetime:
+ // Suppress cleanups for pseudo-strong variables.
+ if (var->isARCPseudoStrong()) return;
+
+ // Otherwise, consider whether to use an EH cleanup or not.
+ cleanupKind = getARCCleanupKind();
+
+ // Use the imprecise destroyer by default.
+ if (!var->hasAttr<ObjCPreciseLifetimeAttr>())
+ destroyer = CodeGenFunction::destroyARCStrongImprecise;
+ break;
+
+ case QualType::DK_objc_weak_lifetime:
+ break;
+ }
+
+ // If we haven't chosen a more specific destroyer, use the default.
+ if (!destroyer) destroyer = &getDestroyer(dtorKind);
+
+ // Use an EH cleanup in array destructors iff the destructor itself
+ // is being pushed as an EH cleanup.
+ bool useEHCleanup = (cleanupKind & EHCleanup);
+ EHStack.pushCleanup<DestroyObject>(cleanupKind, addr, type, destroyer,
+ useEHCleanup);
+}
+
void CodeGenFunction::EmitAutoVarCleanups(const AutoVarEmission &emission) {
assert(emission.Variable && "emission was not valid!");
@@ -799,35 +1089,14 @@ void CodeGenFunction::EmitAutoVarCleanups(const AutoVarEmission &emission) {
const VarDecl &D = *emission.Variable;
- // Handle C++ destruction of variables.
- if (getLangOptions().CPlusPlus) {
- QualType type = D.getType();
- QualType baseType = getContext().getBaseElementType(type);
- if (const RecordType *RT = baseType->getAs<RecordType>()) {
- CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(RT->getDecl());
- if (!ClassDecl->hasTrivialDestructor()) {
- // Note: We suppress the destructor call when the corresponding NRVO
- // flag has been set.
-
- // Note that for __block variables, we want to destroy the
- // original stack object, not the possible forwarded object.
- llvm::Value *Loc = emission.getObjectAddress(*this);
-
- const CXXDestructorDecl *D = ClassDecl->getDestructor();
- assert(D && "EmitLocalBlockVarDecl - destructor is nul");
-
- if (type != baseType) {
- const ConstantArrayType *Array =
- getContext().getAsConstantArrayType(type);
- assert(Array && "types changed without array?");
- EHStack.pushCleanup<CallArrayDtor>(NormalAndEHCleanup,
- D, Array, Loc);
- } else {
- EHStack.pushCleanup<CallVarDtor>(NormalAndEHCleanup,
- D, emission.NRVOFlag, Loc);
- }
- }
- }
+ // Check the type for a cleanup.
+ if (QualType::DestructionKind dtorKind = D.getType().isDestructedType())
+ emitAutoVarTypeCleanup(emission, dtorKind);
+
+ // In GC mode, honor objc_precise_lifetime.
+ if (getLangOptions().getGCMode() != LangOptions::NonGC &&
+ D.hasAttr<ObjCPreciseLifetimeAttr>()) {
+ EHStack.pushCleanup<ExtendGCLifetime>(NormalCleanup, &D);
}
// Handle the cleanup attribute.
@@ -847,6 +1116,271 @@ void CodeGenFunction::EmitAutoVarCleanups(const AutoVarEmission &emission) {
enterByrefCleanup(emission);
}
+CodeGenFunction::Destroyer &
+CodeGenFunction::getDestroyer(QualType::DestructionKind kind) {
+ // This is surprisingly compiler-dependent. GCC 4.2 can't bind
+ // references to functions directly in returns, and using '*&foo'
+ // confuses MSVC. Luckily, the following code pattern works in both.
+ Destroyer *destroyer = 0;
+ switch (kind) {
+ case QualType::DK_none: llvm_unreachable("no destroyer for trivial dtor");
+ case QualType::DK_cxx_destructor:
+ destroyer = &destroyCXXObject;
+ break;
+ case QualType::DK_objc_strong_lifetime:
+ destroyer = &destroyARCStrongPrecise;
+ break;
+ case QualType::DK_objc_weak_lifetime:
+ destroyer = &destroyARCWeak;
+ break;
+ }
+ return *destroyer;
+}
+
+/// pushDestroy - Push the standard destructor for the given type.
+void CodeGenFunction::pushDestroy(QualType::DestructionKind dtorKind,
+ llvm::Value *addr, QualType type) {
+ assert(dtorKind && "cannot push destructor for trivial type");
+
+ CleanupKind cleanupKind = getCleanupKind(dtorKind);
+ pushDestroy(cleanupKind, addr, type, getDestroyer(dtorKind),
+ cleanupKind & EHCleanup);
+}
+
+void CodeGenFunction::pushDestroy(CleanupKind cleanupKind, llvm::Value *addr,
+ QualType type, Destroyer &destroyer,
+ bool useEHCleanupForArray) {
+ pushFullExprCleanup<DestroyObject>(cleanupKind, addr, type,
+ destroyer, useEHCleanupForArray);
+}
+
+/// emitDestroy - Immediately perform the destruction of the given
+/// object.
+///
+/// \param addr - the address of the object; a type*
+/// \param type - the type of the object; if an array type, all
+/// objects are destroyed in reverse order
+/// \param destroyer - the function to call to destroy individual
+/// elements
+/// \param useEHCleanupForArray - whether an EH cleanup should be
+/// used when destroying array elements, in case one of the
+/// destructions throws an exception
+void CodeGenFunction::emitDestroy(llvm::Value *addr, QualType type,
+ Destroyer &destroyer,
+ bool useEHCleanupForArray) {
+ const ArrayType *arrayType = getContext().getAsArrayType(type);
+ if (!arrayType)
+ return destroyer(*this, addr, type);
+
+ llvm::Value *begin = addr;
+ llvm::Value *length = emitArrayLength(arrayType, type, begin);
+
+ // Normally we have to check whether the array is zero-length.
+ bool checkZeroLength = true;
+
+ // But if the array length is constant, we can suppress that.
+ if (llvm::ConstantInt *constLength = dyn_cast<llvm::ConstantInt>(length)) {
+ // ...and if it's constant zero, we can just skip the entire thing.
+ if (constLength->isZero()) return;
+ checkZeroLength = false;
+ }
+
+ llvm::Value *end = Builder.CreateInBoundsGEP(begin, length);
+ emitArrayDestroy(begin, end, type, destroyer,
+ checkZeroLength, useEHCleanupForArray);
+}
+
+/// emitArrayDestroy - Destroys all the elements of the given array,
+/// beginning from last to first. The array cannot be zero-length.
+///
+/// \param begin - a type* denoting the first element of the array
+/// \param end - a type* denoting one past the end of the array
+/// \param type - the element type of the array
+/// \param destroyer - the function to call to destroy elements
+/// \param useEHCleanup - whether to push an EH cleanup to destroy
+/// the remaining elements in case the destruction of a single
+/// element throws
+void CodeGenFunction::emitArrayDestroy(llvm::Value *begin,
+ llvm::Value *end,
+ QualType type,
+ Destroyer &destroyer,
+ bool checkZeroLength,
+ bool useEHCleanup) {
+ assert(!type->isArrayType());
+
+ // The basic structure here is a do-while loop, because we don't
+ // need to check for the zero-element case.
+ llvm::BasicBlock *bodyBB = createBasicBlock("arraydestroy.body");
+ llvm::BasicBlock *doneBB = createBasicBlock("arraydestroy.done");
+
+ if (checkZeroLength) {
+ llvm::Value *isEmpty = Builder.CreateICmpEQ(begin, end,
+ "arraydestroy.isempty");
+ Builder.CreateCondBr(isEmpty, doneBB, bodyBB);
+ }
+
+ // Enter the loop body, making that address the current address.
+ llvm::BasicBlock *entryBB = Builder.GetInsertBlock();
+ EmitBlock(bodyBB);
+ llvm::PHINode *elementPast =
+ Builder.CreatePHI(begin->getType(), 2, "arraydestroy.elementPast");
+ elementPast->addIncoming(end, entryBB);
+
+ // Shift the address back by one element.
+ llvm::Value *negativeOne = llvm::ConstantInt::get(SizeTy, -1, true);
+ llvm::Value *element = Builder.CreateInBoundsGEP(elementPast, negativeOne,
+ "arraydestroy.element");
+
+ if (useEHCleanup)
+ pushRegularPartialArrayCleanup(begin, element, type, destroyer);
+
+ // Perform the actual destruction there.
+ destroyer(*this, element, type);
+
+ if (useEHCleanup)
+ PopCleanupBlock();
+
+ // Check whether we've reached the end.
+ llvm::Value *done = Builder.CreateICmpEQ(element, begin, "arraydestroy.done");
+ Builder.CreateCondBr(done, doneBB, bodyBB);
+ elementPast->addIncoming(element, Builder.GetInsertBlock());
+
+ // Done.
+ EmitBlock(doneBB);
+}
+
+/// Perform partial array destruction as if in an EH cleanup. Unlike
+/// emitArrayDestroy, the element type here may still be an array type.
+static void emitPartialArrayDestroy(CodeGenFunction &CGF,
+ llvm::Value *begin, llvm::Value *end,
+ QualType type,
+ CodeGenFunction::Destroyer &destroyer) {
+ // If the element type is itself an array, drill down.
+ unsigned arrayDepth = 0;
+ while (const ArrayType *arrayType = CGF.getContext().getAsArrayType(type)) {
+ // VLAs don't require a GEP index to walk into.
+ if (!isa<VariableArrayType>(arrayType))
+ arrayDepth++;
+ type = arrayType->getElementType();
+ }
+
+ if (arrayDepth) {
+ llvm::Value *zero = llvm::ConstantInt::get(CGF.SizeTy, arrayDepth+1);
+
+ llvm::SmallVector<llvm::Value*,4> gepIndices(arrayDepth, zero);
+ begin = CGF.Builder.CreateInBoundsGEP(begin, gepIndices.begin(),
+ gepIndices.end(), "pad.arraybegin");
+ end = CGF.Builder.CreateInBoundsGEP(end, gepIndices.begin(),
+ gepIndices.end(), "pad.arrayend");
+ }
+
+ // Destroy the array. We don't ever need an EH cleanup because we
+ // assume that we're in an EH cleanup ourselves, so a throwing
+ // destructor causes an immediate terminate.
+ CGF.emitArrayDestroy(begin, end, type, destroyer,
+ /*checkZeroLength*/ true, /*useEHCleanup*/ false);
+}
+
+namespace {
+ /// RegularPartialArrayDestroy - a cleanup which performs a partial
+ /// array destroy where the end pointer is regularly determined and
+ /// does not need to be loaded from a local.
+ class RegularPartialArrayDestroy : public EHScopeStack::Cleanup {
+ llvm::Value *ArrayBegin;
+ llvm::Value *ArrayEnd;
+ QualType ElementType;
+ CodeGenFunction::Destroyer &Destroyer;
+ public:
+ RegularPartialArrayDestroy(llvm::Value *arrayBegin, llvm::Value *arrayEnd,
+ QualType elementType,
+ CodeGenFunction::Destroyer *destroyer)
+ : ArrayBegin(arrayBegin), ArrayEnd(arrayEnd),
+ ElementType(elementType), Destroyer(*destroyer) {}
+
+ void Emit(CodeGenFunction &CGF, Flags flags) {
+ emitPartialArrayDestroy(CGF, ArrayBegin, ArrayEnd,
+ ElementType, Destroyer);
+ }
+ };
+
+ /// IrregularPartialArrayDestroy - a cleanup which performs a
+ /// partial array destroy where the end pointer is irregularly
+ /// determined and must be loaded from a local.
+ class IrregularPartialArrayDestroy : public EHScopeStack::Cleanup {
+ llvm::Value *ArrayBegin;
+ llvm::Value *ArrayEndPointer;
+ QualType ElementType;
+ CodeGenFunction::Destroyer &Destroyer;
+ public:
+ IrregularPartialArrayDestroy(llvm::Value *arrayBegin,
+ llvm::Value *arrayEndPointer,
+ QualType elementType,
+ CodeGenFunction::Destroyer *destroyer)
+ : ArrayBegin(arrayBegin), ArrayEndPointer(arrayEndPointer),
+ ElementType(elementType), Destroyer(*destroyer) {}
+
+ void Emit(CodeGenFunction &CGF, Flags flags) {
+ llvm::Value *arrayEnd = CGF.Builder.CreateLoad(ArrayEndPointer);
+ emitPartialArrayDestroy(CGF, ArrayBegin, arrayEnd,
+ ElementType, Destroyer);
+ }
+ };
+}
+
+/// pushIrregularPartialArrayCleanup - Push an EH cleanup to destroy
+/// already-constructed elements of the given array. The cleanup
+/// may be popped with DeactivateCleanupBlock or PopCleanupBlock.
+///
+/// \param elementType - the immediate element type of the array;
+/// possibly still an array type
+/// \param array - a value of type elementType*
+/// \param destructionKind - the kind of destruction required
+/// \param initializedElementCount - a value of type size_t* holding
+/// the number of successfully-constructed elements
+void CodeGenFunction::pushIrregularPartialArrayCleanup(llvm::Value *arrayBegin,
+ llvm::Value *arrayEndPointer,
+ QualType elementType,
+ Destroyer &destroyer) {
+ pushFullExprCleanup<IrregularPartialArrayDestroy>(EHCleanup,
+ arrayBegin, arrayEndPointer,
+ elementType, &destroyer);
+}
+
+/// pushRegularPartialArrayCleanup - Push an EH cleanup to destroy
+/// already-constructed elements of the given array. The cleanup
+/// may be popped with DeactivateCleanupBlock or PopCleanupBlock.
+///
+/// \param elementType - the immediate element type of the array;
+/// possibly still an array type
+/// \param array - a value of type elementType*
+/// \param destructionKind - the kind of destruction required
+/// \param initializedElementCount - a value of type size_t* holding
+/// the number of successfully-constructed elements
+void CodeGenFunction::pushRegularPartialArrayCleanup(llvm::Value *arrayBegin,
+ llvm::Value *arrayEnd,
+ QualType elementType,
+ Destroyer &destroyer) {
+ pushFullExprCleanup<RegularPartialArrayDestroy>(EHCleanup,
+ arrayBegin, arrayEnd,
+ elementType, &destroyer);
+}
+
+namespace {
+ /// A cleanup to perform a release of an object at the end of a
+ /// function. This is used to balance out the incoming +1 of a
+ /// ns_consumed argument when we can't reasonably do that just by
+ /// not doing the initial retain for a __block argument.
+ struct ConsumeARCParameter : EHScopeStack::Cleanup {
+ ConsumeARCParameter(llvm::Value *param) : Param(param) {}
+
+ llvm::Value *Param;
+
+ void Emit(CodeGenFunction &CGF, Flags flags) {
+ CGF.EmitARCRelease(Param, /*precise*/ false);
+ }
+ };
+}
+
/// Emit an alloca (or GlobalValue depending on target)
/// for the specified parameter and set up LocalDeclMap.
void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg,
@@ -883,10 +1417,56 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg,
// Otherwise, create a temporary to hold the value.
DeclPtr = CreateMemTemp(Ty, D.getName() + ".addr");
+ bool doStore = true;
+
+ Qualifiers qs = Ty.getQualifiers();
+
+ if (Qualifiers::ObjCLifetime lt = qs.getObjCLifetime()) {
+ // We honor __attribute__((ns_consumed)) for types with lifetime.
+ // For __strong, it's handled by just skipping the initial retain;
+ // otherwise we have to balance out the initial +1 with an extra
+ // cleanup to do the release at the end of the function.
+ bool isConsumed = D.hasAttr<NSConsumedAttr>();
+
+ // 'self' is always formally __strong, but if this is not an
+ // init method then we don't want to retain it.
+ if (D.isARCPseudoStrong()) {
+ const ObjCMethodDecl *method = cast<ObjCMethodDecl>(CurCodeDecl);
+ assert(&D == method->getSelfDecl());
+ assert(lt == Qualifiers::OCL_Strong);
+ assert(qs.hasConst());
+ assert(method->getMethodFamily() != OMF_init);
+ (void) method;
+ lt = Qualifiers::OCL_ExplicitNone;
+ }
+
+ if (lt == Qualifiers::OCL_Strong) {
+ if (!isConsumed)
+ // Don't use objc_retainBlock for block pointers, because we
+ // don't want to Block_copy something just because we got it
+ // as a parameter.
+ Arg = EmitARCRetainNonBlock(Arg);
+ } else {
+ // Push the cleanup for a consumed parameter.
+ if (isConsumed)
+ EHStack.pushCleanup<ConsumeARCParameter>(getARCCleanupKind(), Arg);
+
+ if (lt == Qualifiers::OCL_Weak) {
+ EmitARCInitWeak(DeclPtr, Arg);
+ doStore = false; // The weak init is a store, no need to do two
+ }
+ }
+
+ // Enter the cleanup scope.
+ EmitAutoVarWithLifetime(*this, D, DeclPtr, lt);
+ }
+
// Store the initial value into the alloca.
- EmitStoreOfScalar(Arg, DeclPtr, Ty.isVolatileQualified(),
- getContext().getDeclAlign(&D).getQuantity(), Ty,
- CGM.getTBAAInfo(Ty));
+ if (doStore) {
+ LValue lv = MakeAddrLValue(DeclPtr, Ty,
+ getContext().getDeclAlign(&D).getQuantity());
+ EmitStoreOfScalar(Arg, lv);
+ }
}
llvm::Value *&DMEntry = LocalDeclMap[&D];
@@ -894,8 +1474,6 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg,
DMEntry = DeclPtr;
// Emit debug info for param declaration.
- if (CGDebugInfo *DI = getDebugInfo()) {
- DI->setLocation(D.getLocation());
+ if (CGDebugInfo *DI = getDebugInfo())
DI->EmitDeclareOfArgVariable(&D, DeclPtr, ArgNo, Builder);
- }
}
diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp
index 178badd44d81..0ae6a3d2ee90 100644
--- a/lib/CodeGen/CGDeclCXX.cpp
+++ b/lib/CodeGen/CGDeclCXX.cpp
@@ -27,68 +27,76 @@ static void EmitDeclInit(CodeGenFunction &CGF, const VarDecl &D,
"Should not call EmitDeclInit on a reference!");
ASTContext &Context = CGF.getContext();
-
- const Expr *Init = D.getInit();
- QualType T = D.getType();
- bool isVolatile = Context.getCanonicalType(T).isVolatileQualified();
- unsigned Alignment = Context.getDeclAlign(&D).getQuantity();
- if (!CGF.hasAggregateLLVMType(T)) {
- llvm::Value *V = CGF.EmitScalarExpr(Init);
+ unsigned alignment = Context.getDeclAlign(&D).getQuantity();
+ QualType type = D.getType();
+ LValue lv = CGF.MakeAddrLValue(DeclPtr, type, alignment);
+
+ const Expr *Init = D.getInit();
+ if (!CGF.hasAggregateLLVMType(type)) {
CodeGenModule &CGM = CGF.CGM;
- Qualifiers::GC GCAttr = CGM.getContext().getObjCGCAttrKind(T);
- if (GCAttr == Qualifiers::Strong)
- CGM.getObjCRuntime().EmitObjCGlobalAssign(CGF, V, DeclPtr,
- D.isThreadSpecified());
- else if (GCAttr == Qualifiers::Weak)
- CGM.getObjCRuntime().EmitObjCWeakAssign(CGF, V, DeclPtr);
+ if (lv.isObjCStrong())
+ CGM.getObjCRuntime().EmitObjCGlobalAssign(CGF, CGF.EmitScalarExpr(Init),
+ DeclPtr, D.isThreadSpecified());
+ else if (lv.isObjCWeak())
+ CGM.getObjCRuntime().EmitObjCWeakAssign(CGF, CGF.EmitScalarExpr(Init),
+ DeclPtr);
else
- CGF.EmitStoreOfScalar(V, DeclPtr, isVolatile, Alignment, T);
- } else if (T->isAnyComplexType()) {
- CGF.EmitComplexExprIntoAddr(Init, DeclPtr, isVolatile);
+ CGF.EmitScalarInit(Init, &D, lv, false);
+ } else if (type->isAnyComplexType()) {
+ CGF.EmitComplexExprIntoAddr(Init, DeclPtr, lv.isVolatile());
} else {
- CGF.EmitAggExpr(Init, AggValueSlot::forAddr(DeclPtr, isVolatile, true));
+ CGF.EmitAggExpr(Init, AggValueSlot::forLValue(lv, true));
}
}
/// Emit code to cause the destruction of the given variable with
/// static storage duration.
static void EmitDeclDestroy(CodeGenFunction &CGF, const VarDecl &D,
- llvm::Constant *DeclPtr) {
+ llvm::Constant *addr) {
CodeGenModule &CGM = CGF.CGM;
- ASTContext &Context = CGF.getContext();
-
- QualType T = D.getType();
-
- // Drill down past array types.
- const ConstantArrayType *Array = Context.getAsConstantArrayType(T);
- if (Array)
- T = Context.getBaseElementType(Array);
+
+ // FIXME: __attribute__((cleanup)) ?
- /// If that's not a record, we're done.
- /// FIXME: __attribute__((cleanup)) ?
- const RecordType *RT = T->getAs<RecordType>();
- if (!RT)
+ QualType type = D.getType();
+ QualType::DestructionKind dtorKind = type.isDestructedType();
+
+ switch (dtorKind) {
+ case QualType::DK_none:
return;
-
- CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- if (RD->hasTrivialDestructor())
+
+ case QualType::DK_cxx_destructor:
+ break;
+
+ case QualType::DK_objc_strong_lifetime:
+ case QualType::DK_objc_weak_lifetime:
+ // We don't care about releasing objects during process teardown.
return;
-
- CXXDestructorDecl *Dtor = RD->getDestructor();
-
- llvm::Constant *DtorFn;
- if (Array) {
- DtorFn =
- CodeGenFunction(CGM).GenerateCXXAggrDestructorHelper(Dtor, Array,
- DeclPtr);
- const llvm::Type *Int8PtrTy =
- llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
- DeclPtr = llvm::Constant::getNullValue(Int8PtrTy);
- } else
- DtorFn = CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete);
-
- CGF.EmitCXXGlobalDtorRegistration(DtorFn, DeclPtr);
+ }
+
+ llvm::Constant *function;
+ llvm::Constant *argument;
+
+ // Special-case non-array C++ destructors, where there's a function
+ // with the right signature that we can just call.
+ const CXXRecordDecl *record = 0;
+ if (dtorKind == QualType::DK_cxx_destructor &&
+ (record = type->getAsCXXRecordDecl())) {
+ assert(!record->hasTrivialDestructor());
+ CXXDestructorDecl *dtor = record->getDestructor();
+
+ function = CGM.GetAddrOfCXXDestructor(dtor, Dtor_Complete);
+ argument = addr;
+
+ // Otherwise, the standard logic requires a helper function.
+ } else {
+ function = CodeGenFunction(CGM).generateDestroyHelper(addr, type,
+ CGF.getDestroyer(dtorKind),
+ CGF.needsEHCleanup(dtorKind));
+ argument = llvm::Constant::getNullValue(CGF.Int8PtrTy);
+ }
+
+ CGF.EmitCXXGlobalDtorRegistration(function, argument);
}
void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D,
@@ -118,12 +126,13 @@ CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn,
}
// Get the destructor function type
- const llvm::Type *DtorFnTy =
+ llvm::Type *ArgTys[] = { Int8PtrTy };
+ llvm::Type *DtorFnTy =
llvm::FunctionType::get(llvm::Type::getVoidTy(getLLVMContext()),
- Int8PtrTy, false);
+ ArgTys, false);
DtorFnTy = llvm::PointerType::getUnqual(DtorFnTy);
- const llvm::Type *Params[] = { DtorFnTy, Int8PtrTy, Int8PtrTy };
+ llvm::Type *Params[] = { DtorFnTy, Int8PtrTy, Int8PtrTy };
// Get the __cxa_atexit function type
// extern "C" int __cxa_atexit ( void (*f)(void *), void *p, void *d );
@@ -140,7 +149,7 @@ CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn,
llvm::Value *Args[3] = { llvm::ConstantExpr::getBitCast(DtorFn, DtorFnTy),
llvm::ConstantExpr::getBitCast(DeclPtr, Int8PtrTy),
llvm::ConstantExpr::getBitCast(Handle, Int8PtrTy) };
- Builder.CreateCall(AtExitFn, &Args[0], llvm::array_endof(Args));
+ Builder.CreateCall(AtExitFn, Args);
}
void CodeGenFunction::EmitCXXGuardedInit(const VarDecl &D,
@@ -270,12 +279,11 @@ void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn,
getTypes().getNullaryFunctionInfo(),
FunctionArgList(), SourceLocation());
- // Use guarded initialization if the global variable is weak due to
- // being a class template's static data member. These will always
- // have weak_odr linkage.
- if (Addr->getLinkage() == llvm::GlobalValue::WeakODRLinkage &&
- D->isStaticDataMember() &&
- D->getInstantiatedFromStaticDataMember()) {
+ // Use guarded initialization if the global variable is weak. This
+ // occurs for, e.g., instantiated static data members and
+ // definitions explicitly marked weak.
+ if (Addr->getLinkage() == llvm::GlobalValue::WeakODRLinkage ||
+ Addr->getLinkage() == llvm::GlobalValue::WeakAnyLinkage) {
EmitCXXGuardedInit(*D, Addr);
} else {
EmitCXXGlobalVarDeclInit(*D, Addr);
@@ -291,10 +299,21 @@ void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
getTypes().getNullaryFunctionInfo(),
FunctionArgList(), SourceLocation());
+ RunCleanupsScope Scope(*this);
+
+ // When building in Objective-C++ ARC mode, create an autorelease pool
+ // around the global initializers.
+ if (getLangOptions().ObjCAutoRefCount && getLangOptions().CPlusPlus) {
+ llvm::Value *token = EmitObjCAutoreleasePoolPush();
+ EmitObjCAutoreleasePoolCleanup(token);
+ }
+
for (unsigned i = 0; i != NumDecls; ++i)
if (Decls[i])
- Builder.CreateCall(Decls[i]);
+ Builder.CreateCall(Decls[i]);
+ Scope.ForceCleanup();
+
FinishFunction();
}
@@ -318,13 +337,13 @@ void CodeGenFunction::GenerateCXXGlobalDtorFunc(llvm::Function *Fn,
FinishFunction();
}
-/// GenerateCXXAggrDestructorHelper - Generates a helper function which when
-/// invoked, calls the default destructor on array elements in reverse order of
-/// construction.
+/// generateDestroyHelper - Generates a helper function which, when
+/// invoked, destroys the given object.
llvm::Function *
-CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D,
- const ArrayType *Array,
- llvm::Value *This) {
+CodeGenFunction::generateDestroyHelper(llvm::Constant *addr,
+ QualType type,
+ Destroyer &destroyer,
+ bool useEHCleanupForArray) {
FunctionArgList args;
ImplicitParamDecl dst(0, SourceLocation(), 0, getContext().VoidPtrTy);
args.push_back(&dst);
@@ -333,19 +352,16 @@ CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D,
CGM.getTypes().getFunctionInfo(getContext().VoidTy, args,
FunctionType::ExtInfo());
const llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI, false);
- llvm::Function *Fn =
+ llvm::Function *fn =
CreateGlobalInitOrDestructFunction(CGM, FTy, "__cxx_global_array_dtor");
- StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FI, args,
+ StartFunction(GlobalDecl(), getContext().VoidTy, fn, FI, args,
SourceLocation());
- QualType BaseElementTy = getContext().getBaseElementType(Array);
- const llvm::Type *BasePtr = ConvertType(BaseElementTy)->getPointerTo();
- llvm::Value *BaseAddrPtr = Builder.CreateBitCast(This, BasePtr);
-
- EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr);
+ emitDestroy(addr, type, destroyer, useEHCleanupForArray);
FinishFunction();
- return Fn;
+ return fn;
}
+
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp
index e8ad6da2f980..418bea6ee402 100644
--- a/lib/CodeGen/CGException.cpp
+++ b/lib/CodeGen/CGException.cpp
@@ -29,10 +29,9 @@ using namespace CodeGen;
static llvm::Constant *getAllocateExceptionFn(CodeGenFunction &CGF) {
// void *__cxa_allocate_exception(size_t thrown_size);
- const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType());
+ llvm::Type *ArgTys[] = { CGF.SizeTy };
const llvm::FunctionType *FTy =
- llvm::FunctionType::get(llvm::Type::getInt8PtrTy(CGF.getLLVMContext()),
- SizeTy, /*IsVarArgs=*/false);
+ llvm::FunctionType::get(CGF.Int8PtrTy, ArgTys, /*IsVarArgs=*/false);
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_allocate_exception");
}
@@ -40,10 +39,9 @@ static llvm::Constant *getAllocateExceptionFn(CodeGenFunction &CGF) {
static llvm::Constant *getFreeExceptionFn(CodeGenFunction &CGF) {
// void __cxa_free_exception(void *thrown_exception);
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
+ llvm::Type *ArgTys[] = { CGF.Int8PtrTy };
const llvm::FunctionType *FTy =
- llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()),
- Int8PtrTy, /*IsVarArgs=*/false);
+ llvm::FunctionType::get(CGF.VoidTy, ArgTys, /*IsVarArgs=*/false);
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_free_exception");
}
@@ -52,11 +50,9 @@ static llvm::Constant *getThrowFn(CodeGenFunction &CGF) {
// void __cxa_throw(void *thrown_exception, std::type_info *tinfo,
// void (*dest) (void *));
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
- const llvm::Type *Args[3] = { Int8PtrTy, Int8PtrTy, Int8PtrTy };
+ llvm::Type *Args[3] = { CGF.Int8PtrTy, CGF.Int8PtrTy, CGF.Int8PtrTy };
const llvm::FunctionType *FTy =
- llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()),
- Args, /*IsVarArgs=*/false);
+ llvm::FunctionType::get(CGF.VoidTy, Args, /*IsVarArgs=*/false);
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_throw");
}
@@ -65,8 +61,7 @@ static llvm::Constant *getReThrowFn(CodeGenFunction &CGF) {
// void __cxa_rethrow();
const llvm::FunctionType *FTy =
- llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()),
- /*IsVarArgs=*/false);
+ llvm::FunctionType::get(CGF.VoidTy, /*IsVarArgs=*/false);
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_rethrow");
}
@@ -74,9 +69,9 @@ static llvm::Constant *getReThrowFn(CodeGenFunction &CGF) {
static llvm::Constant *getGetExceptionPtrFn(CodeGenFunction &CGF) {
// void *__cxa_get_exception_ptr(void*);
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
+ llvm::Type *ArgTys[] = { CGF.Int8PtrTy };
const llvm::FunctionType *FTy =
- llvm::FunctionType::get(Int8PtrTy, Int8PtrTy, /*IsVarArgs=*/false);
+ llvm::FunctionType::get(CGF.Int8PtrTy, ArgTys, /*IsVarArgs=*/false);
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_get_exception_ptr");
}
@@ -84,9 +79,9 @@ static llvm::Constant *getGetExceptionPtrFn(CodeGenFunction &CGF) {
static llvm::Constant *getBeginCatchFn(CodeGenFunction &CGF) {
// void *__cxa_begin_catch(void*);
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
+ llvm::Type *ArgTys[] = { CGF.Int8PtrTy };
const llvm::FunctionType *FTy =
- llvm::FunctionType::get(Int8PtrTy, Int8PtrTy, /*IsVarArgs=*/false);
+ llvm::FunctionType::get(CGF.Int8PtrTy, ArgTys, /*IsVarArgs=*/false);
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_begin_catch");
}
@@ -95,8 +90,7 @@ static llvm::Constant *getEndCatchFn(CodeGenFunction &CGF) {
// void __cxa_end_catch();
const llvm::FunctionType *FTy =
- llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()),
- /*IsVarArgs=*/false);
+ llvm::FunctionType::get(CGF.VoidTy, /*IsVarArgs=*/false);
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_end_catch");
}
@@ -104,17 +98,17 @@ static llvm::Constant *getEndCatchFn(CodeGenFunction &CGF) {
static llvm::Constant *getUnexpectedFn(CodeGenFunction &CGF) {
// void __cxa_call_unexepcted(void *thrown_exception);
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
+ llvm::Type *ArgTys[] = { CGF.Int8PtrTy };
const llvm::FunctionType *FTy =
- llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()),
- Int8PtrTy, /*IsVarArgs=*/false);
+ llvm::FunctionType::get(CGF.VoidTy, ArgTys, /*IsVarArgs=*/false);
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_call_unexpected");
}
llvm::Constant *CodeGenFunction::getUnwindResumeFn() {
+ llvm::Type *ArgTys[] = { Int8PtrTy };
const llvm::FunctionType *FTy =
- llvm::FunctionType::get(VoidTy, Int8PtrTy, /*IsVarArgs=*/false);
+ llvm::FunctionType::get(VoidTy, ArgTys, /*IsVarArgs=*/false);
if (CGM.getLangOptions().SjLjExceptions)
return CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume");
@@ -122,8 +116,9 @@ llvm::Constant *CodeGenFunction::getUnwindResumeFn() {
}
llvm::Constant *CodeGenFunction::getUnwindResumeOrRethrowFn() {
+ llvm::Type *ArgTys[] = { Int8PtrTy };
const llvm::FunctionType *FTy =
- llvm::FunctionType::get(VoidTy, Int8PtrTy, /*IsVarArgs=*/false);
+ llvm::FunctionType::get(VoidTy, ArgTys, /*IsVarArgs=*/false);
if (CGM.getLangOptions().SjLjExceptions)
return CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume_or_Rethrow");
@@ -134,20 +129,26 @@ static llvm::Constant *getTerminateFn(CodeGenFunction &CGF) {
// void __terminate();
const llvm::FunctionType *FTy =
- llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()),
- /*IsVarArgs=*/false);
+ llvm::FunctionType::get(CGF.VoidTy, /*IsVarArgs=*/false);
- return CGF.CGM.CreateRuntimeFunction(FTy,
- CGF.CGM.getLangOptions().CPlusPlus ? "_ZSt9terminatev" : "abort");
+ llvm::StringRef name;
+
+ // In C++, use std::terminate().
+ if (CGF.getLangOptions().CPlusPlus)
+ name = "_ZSt9terminatev"; // FIXME: mangling!
+ else if (CGF.getLangOptions().ObjC1 &&
+ CGF.CGM.getCodeGenOpts().ObjCRuntimeHasTerminate)
+ name = "objc_terminate";
+ else
+ name = "abort";
+ return CGF.CGM.CreateRuntimeFunction(FTy, name);
}
static llvm::Constant *getCatchallRethrowFn(CodeGenFunction &CGF,
llvm::StringRef Name) {
- const llvm::Type *Int8PtrTy =
- llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
- const llvm::Type *VoidTy = llvm::Type::getVoidTy(CGF.getLLVMContext());
- const llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, Int8PtrTy,
- /*IsVarArgs=*/false);
+ llvm::Type *ArgTys[] = { CGF.Int8PtrTy };
+ const llvm::FunctionType *FTy =
+ llvm::FunctionType::get(CGF.VoidTy, ArgTys, /*IsVarArgs=*/false);
return CGF.CGM.CreateRuntimeFunction(FTy, Name);
}
@@ -322,9 +323,10 @@ static llvm::Constant *getCleanupValue(CodeGenFunction &CGF) {
namespace {
/// A cleanup to free the exception object if its initialization
/// throws.
- struct FreeException {
- static void Emit(CodeGenFunction &CGF, bool forEH,
- llvm::Value *exn) {
+ struct FreeException : EHScopeStack::Cleanup {
+ llvm::Value *exn;
+ FreeException(llvm::Value *exn) : exn(exn) {}
+ void Emit(CodeGenFunction &CGF, Flags flags) {
CGF.Builder.CreateCall(getFreeExceptionFn(CGF), exn)
->setDoesNotThrow();
}
@@ -354,7 +356,8 @@ static void EmitAnyExprToExn(CodeGenFunction &CGF, const Expr *e,
// evaluated but before the exception is caught. But the best way
// to handle that is to teach EmitAggExpr to do the final copy
// differently if it can't be elided.
- CGF.EmitAnyExprToMem(e, typedAddr, /*Volatile*/ false, /*IsInit*/ true);
+ CGF.EmitAnyExprToMem(e, typedAddr, e->getType().getQualifiers(),
+ /*IsInit*/ true);
// Deactivate the cleanup block.
CGF.DeactivateCleanupBlock(cleanup);
@@ -407,7 +410,6 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) {
EmitAnyExprToExn(*this, E->getSubExpr(), ExceptionPtr);
// Now throw the exception.
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext());
llvm::Constant *TypeInfo = CGM.GetAddrOfRTTIDescriptor(ThrowType,
/*ForEH=*/true);
@@ -786,7 +788,7 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
// Tell the backend how to generate the landing pad.
llvm::CallInst *Selection =
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::eh_selector),
- EHSelector.begin(), EHSelector.end(), "eh.selector");
+ EHSelector, "eh.selector");
Selection->setDoesNotThrow();
// Save the selector value in mandatory-cleanup mode.
@@ -920,13 +922,13 @@ namespace {
CallEndCatch(bool MightThrow) : MightThrow(MightThrow) {}
bool MightThrow;
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
if (!MightThrow) {
CGF.Builder.CreateCall(getEndCatchFn(CGF))->setDoesNotThrow();
return;
}
- CGF.EmitCallOrInvoke(getEndCatchFn(CGF), 0, 0);
+ CGF.EmitCallOrInvoke(getEndCatchFn(CGF));
}
};
}
@@ -1084,7 +1086,8 @@ static void InitCatchParam(CodeGenFunction &CGF,
CGF.EHStack.pushTerminate();
// Perform the copy construction.
- CGF.EmitAggExpr(copyExpr, AggValueSlot::forAddr(ParamAddr, false, false));
+ CGF.EmitAggExpr(copyExpr, AggValueSlot::forAddr(ParamAddr, Qualifiers(),
+ false));
// Leave the terminate scope.
CGF.EHStack.popTerminate();
@@ -1137,8 +1140,8 @@ static void BeginCatch(CodeGenFunction &CGF, const CXXCatchStmt *S) {
namespace {
struct CallRethrow : EHScopeStack::Cleanup {
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
- CGF.EmitCallOrInvoke(getReThrowFn(CGF), 0, 0);
+ void Emit(CodeGenFunction &CGF, Flags flags) {
+ CGF.EmitCallOrInvoke(getReThrowFn(CGF));
}
};
}
@@ -1209,7 +1212,7 @@ namespace {
CallEndCatchForFinally(llvm::Value *ForEHVar, llvm::Value *EndCatchFn)
: ForEHVar(ForEHVar), EndCatchFn(EndCatchFn) {}
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
llvm::BasicBlock *EndCatchBB = CGF.createBasicBlock("finally.endcatch");
llvm::BasicBlock *CleanupContBB =
CGF.createBasicBlock("finally.cleanup.cont");
@@ -1218,7 +1221,7 @@ namespace {
CGF.Builder.CreateLoad(ForEHVar, "finally.endcatch");
CGF.Builder.CreateCondBr(ShouldEndCatch, EndCatchBB, CleanupContBB);
CGF.EmitBlock(EndCatchBB);
- CGF.EmitCallOrInvoke(EndCatchFn, 0, 0); // catch-all, so might throw
+ CGF.EmitCallOrInvoke(EndCatchFn); // catch-all, so might throw
CGF.EmitBlock(CleanupContBB);
}
};
@@ -1236,7 +1239,7 @@ namespace {
: Body(Body), ForEHVar(ForEHVar), EndCatchFn(EndCatchFn),
RethrowFn(RethrowFn), SavedExnVar(SavedExnVar) {}
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
// Enter a cleanup to call the end-catch function if one was provided.
if (EndCatchFn)
CGF.EHStack.pushCleanup<CallEndCatchForFinally>(NormalAndEHCleanup,
@@ -1263,10 +1266,9 @@ namespace {
CGF.EmitBlock(RethrowBB);
if (SavedExnVar) {
- llvm::Value *Args[] = { CGF.Builder.CreateLoad(SavedExnVar) };
- CGF.EmitCallOrInvoke(RethrowFn, Args, Args+1);
+ CGF.EmitCallOrInvoke(RethrowFn, CGF.Builder.CreateLoad(SavedExnVar));
} else {
- CGF.EmitCallOrInvoke(RethrowFn, 0, 0);
+ CGF.EmitCallOrInvoke(RethrowFn);
}
CGF.Builder.CreateUnreachable();
@@ -1296,14 +1298,16 @@ namespace {
/// Enters a finally block for an implementation using zero-cost
/// exceptions. This is mostly general, but hard-codes some
/// language/ABI-specific behavior in the catch-all sections.
-CodeGenFunction::FinallyInfo
-CodeGenFunction::EnterFinallyBlock(const Stmt *Body,
- llvm::Constant *BeginCatchFn,
- llvm::Constant *EndCatchFn,
- llvm::Constant *RethrowFn) {
- assert((BeginCatchFn != 0) == (EndCatchFn != 0) &&
+void CodeGenFunction::FinallyInfo::enter(CodeGenFunction &CGF,
+ const Stmt *body,
+ llvm::Constant *beginCatchFn,
+ llvm::Constant *endCatchFn,
+ llvm::Constant *rethrowFn) {
+ assert((beginCatchFn != 0) == (endCatchFn != 0) &&
"begin/end catch functions not paired");
- assert(RethrowFn && "rethrow function is required");
+ assert(rethrowFn && "rethrow function is required");
+
+ BeginCatchFn = beginCatchFn;
// The rethrow function has one of the following two types:
// void (*)()
@@ -1311,13 +1315,12 @@ CodeGenFunction::EnterFinallyBlock(const Stmt *Body,
// In the latter case we need to pass it the exception object.
// But we can't use the exception slot because the @finally might
// have a landing pad (which would overwrite the exception slot).
- const llvm::FunctionType *RethrowFnTy =
+ const llvm::FunctionType *rethrowFnTy =
cast<llvm::FunctionType>(
- cast<llvm::PointerType>(RethrowFn->getType())
- ->getElementType());
- llvm::Value *SavedExnVar = 0;
- if (RethrowFnTy->getNumParams())
- SavedExnVar = CreateTempAlloca(Builder.getInt8PtrTy(), "finally.exn");
+ cast<llvm::PointerType>(rethrowFn->getType())->getElementType());
+ SavedExnVar = 0;
+ if (rethrowFnTy->getNumParams())
+ SavedExnVar = CGF.CreateTempAlloca(CGF.Int8PtrTy, "finally.exn");
// A finally block is a statement which must be executed on any edge
// out of a given scope. Unlike a cleanup, the finally block may
@@ -1331,67 +1334,64 @@ CodeGenFunction::EnterFinallyBlock(const Stmt *Body,
// The finally block itself is generated in the context of a cleanup
// which conditionally leaves the catch-all.
- FinallyInfo Info;
-
// Jump destination for performing the finally block on an exception
// edge. We'll never actually reach this block, so unreachable is
// fine.
- JumpDest RethrowDest = getJumpDestInCurrentScope(getUnreachableBlock());
+ RethrowDest = CGF.getJumpDestInCurrentScope(CGF.getUnreachableBlock());
// Whether the finally block is being executed for EH purposes.
- llvm::AllocaInst *ForEHVar = CreateTempAlloca(Builder.getInt1Ty(),
- "finally.for-eh");
- InitTempAlloca(ForEHVar, llvm::ConstantInt::getFalse(getLLVMContext()));
+ ForEHVar = CGF.CreateTempAlloca(CGF.Builder.getInt1Ty(), "finally.for-eh");
+ CGF.Builder.CreateStore(CGF.Builder.getFalse(), ForEHVar);
// Enter a normal cleanup which will perform the @finally block.
- EHStack.pushCleanup<PerformFinally>(NormalCleanup, Body,
- ForEHVar, EndCatchFn,
- RethrowFn, SavedExnVar);
+ CGF.EHStack.pushCleanup<PerformFinally>(NormalCleanup, body,
+ ForEHVar, endCatchFn,
+ rethrowFn, SavedExnVar);
// Enter a catch-all scope.
- llvm::BasicBlock *CatchAllBB = createBasicBlock("finally.catchall");
- CGBuilderTy::InsertPoint SavedIP = Builder.saveIP();
- Builder.SetInsertPoint(CatchAllBB);
-
- // If there's a begin-catch function, call it.
- if (BeginCatchFn) {
- Builder.CreateCall(BeginCatchFn, Builder.CreateLoad(getExceptionSlot()))
- ->setDoesNotThrow();
- }
-
- // If we need to remember the exception pointer to rethrow later, do so.
- if (SavedExnVar) {
- llvm::Value *SavedExn = Builder.CreateLoad(getExceptionSlot());
- Builder.CreateStore(SavedExn, SavedExnVar);
- }
+ llvm::BasicBlock *catchBB = CGF.createBasicBlock("finally.catchall");
+ EHCatchScope *catchScope = CGF.EHStack.pushCatch(1);
+ catchScope->setCatchAllHandler(0, catchBB);
+}
- // Tell the finally block that we're in EH.
- Builder.CreateStore(llvm::ConstantInt::getTrue(getLLVMContext()), ForEHVar);
+void CodeGenFunction::FinallyInfo::exit(CodeGenFunction &CGF) {
+ // Leave the finally catch-all.
+ EHCatchScope &catchScope = cast<EHCatchScope>(*CGF.EHStack.begin());
+ llvm::BasicBlock *catchBB = catchScope.getHandler(0).Block;
+ CGF.EHStack.popCatch();
- // Thread a jump through the finally cleanup.
- EmitBranchThroughCleanup(RethrowDest);
+ // If there are any references to the catch-all block, emit it.
+ if (catchBB->use_empty()) {
+ delete catchBB;
+ } else {
+ CGBuilderTy::InsertPoint savedIP = CGF.Builder.saveAndClearIP();
+ CGF.EmitBlock(catchBB);
- Builder.restoreIP(SavedIP);
+ llvm::Value *exn = 0;
- EHCatchScope *CatchScope = EHStack.pushCatch(1);
- CatchScope->setCatchAllHandler(0, CatchAllBB);
+ // If there's a begin-catch function, call it.
+ if (BeginCatchFn) {
+ exn = CGF.Builder.CreateLoad(CGF.getExceptionSlot());
+ CGF.Builder.CreateCall(BeginCatchFn, exn)->setDoesNotThrow();
+ }
- return Info;
-}
+ // If we need to remember the exception pointer to rethrow later, do so.
+ if (SavedExnVar) {
+ if (!exn) exn = CGF.Builder.CreateLoad(CGF.getExceptionSlot());
+ CGF.Builder.CreateStore(exn, SavedExnVar);
+ }
-void CodeGenFunction::ExitFinallyBlock(FinallyInfo &Info) {
- // Leave the finally catch-all.
- EHCatchScope &Catch = cast<EHCatchScope>(*EHStack.begin());
- llvm::BasicBlock *CatchAllBB = Catch.getHandler(0).Block;
- EHStack.popCatch();
+ // Tell the cleanups in the finally block that we're do this for EH.
+ CGF.Builder.CreateStore(CGF.Builder.getTrue(), ForEHVar);
- // And leave the normal cleanup.
- PopCleanupBlock();
+ // Thread a jump through the finally cleanup.
+ CGF.EmitBranchThroughCleanup(RethrowDest);
- CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP();
- EmitBlock(CatchAllBB, true);
+ CGF.Builder.restoreIP(savedIP);
+ }
- Builder.restoreIP(SavedIP);
+ // Finally, leave the @finally cleanup.
+ CGF.PopCleanupBlock();
}
llvm::BasicBlock *CodeGenFunction::getTerminateLandingPad() {
@@ -1416,7 +1416,7 @@ llvm::BasicBlock *CodeGenFunction::getTerminateLandingPad() {
llvm::Value *Args[3] = { Exn, getOpaquePersonalityFn(CGM, Personality),
getCatchAllValue(*this) };
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::eh_selector),
- Args, Args+3, "eh.selector")
+ Args, "eh.selector")
->setDoesNotThrow();
llvm::CallInst *TerminateCall = Builder.CreateCall(getTerminateFn(*this));
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 2f6b55bd7b0b..a7e8003eaab5 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -20,8 +20,8 @@
#include "CGObjCRuntime.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
-#include "llvm/Intrinsics.h"
#include "clang/Frontend/CodeGenOptions.h"
+#include "llvm/Intrinsics.h"
#include "llvm/Target/TargetData.h"
using namespace clang;
using namespace CodeGen;
@@ -131,16 +131,16 @@ RValue CodeGenFunction::EmitAnyExprToTemp(const Expr *E) {
/// location.
void CodeGenFunction::EmitAnyExprToMem(const Expr *E,
llvm::Value *Location,
- bool IsLocationVolatile,
+ Qualifiers Quals,
bool IsInit) {
- if (E->getType()->isComplexType())
- EmitComplexExprIntoAddr(E, Location, IsLocationVolatile);
+ if (E->getType()->isAnyComplexType())
+ EmitComplexExprIntoAddr(E, Location, Quals.hasVolatile());
else if (hasAggregateLLVMType(E->getType()))
- EmitAggExpr(E, AggValueSlot::forAddr(Location, IsLocationVolatile, IsInit));
+ EmitAggExpr(E, AggValueSlot::forAddr(Location, Quals, IsInit));
else {
RValue RV = RValue::get(EmitScalarExpr(E, /*Ignore*/ false));
LValue LV = MakeAddrLValue(Location, E->getType());
- EmitStoreThroughLValue(RV, LV, E->getType());
+ EmitStoreThroughLValue(RV, LV);
}
}
@@ -203,7 +203,24 @@ static llvm::Value *
EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
llvm::Value *&ReferenceTemporary,
const CXXDestructorDecl *&ReferenceTemporaryDtor,
+ QualType &ObjCARCReferenceLifetimeType,
const NamedDecl *InitializedDecl) {
+ // Look through expressions for materialized temporaries (for now).
+ if (const MaterializeTemporaryExpr *M
+ = dyn_cast<MaterializeTemporaryExpr>(E)) {
+ // Objective-C++ ARC:
+ // If we are binding a reference to a temporary that has ownership, we
+ // need to perform retain/release operations on the temporary.
+ if (CGF.getContext().getLangOptions().ObjCAutoRefCount &&
+ E->getType()->isObjCLifetimeType() &&
+ (E->getType().getObjCLifetime() == Qualifiers::OCL_Strong ||
+ E->getType().getObjCLifetime() == Qualifiers::OCL_Weak ||
+ E->getType().getObjCLifetime() == Qualifiers::OCL_Autoreleasing))
+ ObjCARCReferenceLifetimeType = E->getType();
+
+ E = M->GetTemporaryExpr();
+ }
+
if (const CXXDefaultArgExpr *DAE = dyn_cast<CXXDefaultArgExpr>(E))
E = DAE->getExpr();
@@ -213,6 +230,7 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
return EmitExprForReferenceBinding(CGF, TE->getSubExpr(),
ReferenceTemporary,
ReferenceTemporaryDtor,
+ ObjCARCReferenceLifetimeType,
InitializedDecl);
}
@@ -229,12 +247,69 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
RV = CGF.EmitLoadOfPropertyRefLValue(LV);
return RV.getScalarVal();
}
+
if (LV.isSimple())
return LV.getAddress();
// We have to load the lvalue.
- RV = CGF.EmitLoadOfLValue(LV, E->getType());
+ RV = CGF.EmitLoadOfLValue(LV);
} else {
+ if (!ObjCARCReferenceLifetimeType.isNull()) {
+ ReferenceTemporary = CreateReferenceTemporary(CGF,
+ ObjCARCReferenceLifetimeType,
+ InitializedDecl);
+
+
+ LValue RefTempDst = CGF.MakeAddrLValue(ReferenceTemporary,
+ ObjCARCReferenceLifetimeType);
+
+ CGF.EmitScalarInit(E, dyn_cast_or_null<ValueDecl>(InitializedDecl),
+ RefTempDst, false);
+
+ bool ExtendsLifeOfTemporary = false;
+ if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(InitializedDecl)) {
+ if (Var->extendsLifetimeOfTemporary())
+ ExtendsLifeOfTemporary = true;
+ } else if (InitializedDecl && isa<FieldDecl>(InitializedDecl)) {
+ ExtendsLifeOfTemporary = true;
+ }
+
+ if (!ExtendsLifeOfTemporary) {
+ // Since the lifetime of this temporary isn't going to be extended,
+ // we need to clean it up ourselves at the end of the full expression.
+ switch (ObjCARCReferenceLifetimeType.getObjCLifetime()) {
+ case Qualifiers::OCL_None:
+ case Qualifiers::OCL_ExplicitNone:
+ case Qualifiers::OCL_Autoreleasing:
+ break;
+
+ case Qualifiers::OCL_Strong: {
+ assert(!ObjCARCReferenceLifetimeType->isArrayType());
+ CleanupKind cleanupKind = CGF.getARCCleanupKind();
+ CGF.pushDestroy(cleanupKind,
+ ReferenceTemporary,
+ ObjCARCReferenceLifetimeType,
+ CodeGenFunction::destroyARCStrongImprecise,
+ cleanupKind & EHCleanup);
+ break;
+ }
+
+ case Qualifiers::OCL_Weak:
+ assert(!ObjCARCReferenceLifetimeType->isArrayType());
+ CGF.pushDestroy(NormalAndEHCleanup,
+ ReferenceTemporary,
+ ObjCARCReferenceLifetimeType,
+ CodeGenFunction::destroyARCWeak,
+ /*useEHCleanupForArray*/ true);
+ break;
+ }
+
+ ObjCARCReferenceLifetimeType = QualType();
+ }
+
+ return ReferenceTemporary;
+ }
+
llvm::SmallVector<SubobjectAdjustment, 2> Adjustments;
while (true) {
E = E->IgnoreParens();
@@ -279,12 +354,10 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
!E->getType()->isAnyComplexType()) {
ReferenceTemporary = CreateReferenceTemporary(CGF, E->getType(),
InitializedDecl);
- AggSlot = AggValueSlot::forAddr(ReferenceTemporary, false,
+ AggSlot = AggValueSlot::forAddr(ReferenceTemporary, Qualifiers(),
InitializedDecl != 0);
}
-
- RV = CGF.EmitAnyExpr(E, AggSlot);
-
+
if (InitializedDecl) {
// Get the destructor for the reference temporary.
if (const RecordType *RT = E->getType()->getAs<RecordType>()) {
@@ -294,6 +367,8 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
}
}
+ RV = CGF.EmitAnyExpr(E, AggSlot);
+
// Check if need to perform derived-to-base casts and/or field accesses, to
// get from the temporary object we created (and, potentially, for which we
// extended the lifetime) to the subobject we're binding the reference to.
@@ -326,7 +401,7 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
Object = CreateReferenceTemporary(CGF, T, InitializedDecl);
LValue TempLV = CGF.MakeAddrLValue(Object,
Adjustment.Field->getType());
- CGF.EmitStoreThroughLValue(CGF.EmitLoadOfLValue(LV, T), TempLV, T);
+ CGF.EmitStoreThroughLValue(CGF.EmitLoadOfLValue(LV), TempLV);
break;
}
@@ -361,26 +436,65 @@ CodeGenFunction::EmitReferenceBindingToExpr(const Expr *E,
const NamedDecl *InitializedDecl) {
llvm::Value *ReferenceTemporary = 0;
const CXXDestructorDecl *ReferenceTemporaryDtor = 0;
+ QualType ObjCARCReferenceLifetimeType;
llvm::Value *Value = EmitExprForReferenceBinding(*this, E, ReferenceTemporary,
ReferenceTemporaryDtor,
+ ObjCARCReferenceLifetimeType,
InitializedDecl);
- if (!ReferenceTemporaryDtor)
+ if (!ReferenceTemporaryDtor && ObjCARCReferenceLifetimeType.isNull())
return RValue::get(Value);
// Make sure to call the destructor for the reference temporary.
- if (const VarDecl *VD = dyn_cast_or_null<VarDecl>(InitializedDecl)) {
- if (VD->hasGlobalStorage()) {
+ const VarDecl *VD = dyn_cast_or_null<VarDecl>(InitializedDecl);
+ if (VD && VD->hasGlobalStorage()) {
+ if (ReferenceTemporaryDtor) {
llvm::Constant *DtorFn =
CGM.GetAddrOfCXXDestructor(ReferenceTemporaryDtor, Dtor_Complete);
EmitCXXGlobalDtorRegistration(DtorFn,
cast<llvm::Constant>(ReferenceTemporary));
-
- return RValue::get(Value);
+ } else {
+ assert(!ObjCARCReferenceLifetimeType.isNull());
+ // Note: We intentionally do not register a global "destructor" to
+ // release the object.
}
+
+ return RValue::get(Value);
}
- PushDestructorCleanup(ReferenceTemporaryDtor, ReferenceTemporary);
-
+ if (ReferenceTemporaryDtor)
+ PushDestructorCleanup(ReferenceTemporaryDtor, ReferenceTemporary);
+ else {
+ switch (ObjCARCReferenceLifetimeType.getObjCLifetime()) {
+ case Qualifiers::OCL_None:
+ assert(0 && "Not a reference temporary that needs to be deallocated");
+ case Qualifiers::OCL_ExplicitNone:
+ case Qualifiers::OCL_Autoreleasing:
+ // Nothing to do.
+ break;
+
+ case Qualifiers::OCL_Strong: {
+ bool precise = VD && VD->hasAttr<ObjCPreciseLifetimeAttr>();
+ CleanupKind cleanupKind = getARCCleanupKind();
+ // This local is a GCC and MSVC compiler workaround.
+ Destroyer *destroyer = precise ? &destroyARCStrongPrecise :
+ &destroyARCStrongImprecise;
+ pushDestroy(cleanupKind, ReferenceTemporary, ObjCARCReferenceLifetimeType,
+ *destroyer, cleanupKind & EHCleanup);
+ break;
+ }
+
+ case Qualifiers::OCL_Weak: {
+ // This local is a GCC and MSVC compiler workaround.
+ Destroyer *destroyer = &destroyARCWeak;
+ // __weak objects always get EH cleanups; otherwise, exceptions
+ // could cause really nasty crashes instead of mere leaks.
+ pushDestroy(NormalAndEHCleanup, ReferenceTemporary,
+ ObjCARCReferenceLifetimeType, *destroyer, true);
+ break;
+ }
+ }
+ }
+
return RValue::get(Value);
}
@@ -402,8 +516,7 @@ void CodeGenFunction::EmitCheck(llvm::Value *Address, unsigned Size) {
// This needs to be to the standard address space.
Address = Builder.CreateBitCast(Address, Int8PtrTy);
- const llvm::Type *IntPtrT = IntPtrTy;
- llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::objectsize, &IntPtrT, 1);
+ llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::objectsize, IntPtrTy);
// In time, people may want to control this and use a 1 here.
llvm::Value *Arg = Builder.getFalse();
@@ -592,6 +705,8 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
return EmitLValue(cast<ChooseExpr>(E)->getChosenSubExpr(getContext()));
case Expr::OpaqueValueExprClass:
return EmitOpaqueValueLValue(cast<OpaqueValueExpr>(E));
+ case Expr::SubstNonTypeTemplateParmExprClass:
+ return EmitLValue(cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement());
case Expr::ImplicitCastExprClass:
case Expr::CStyleCastExprClass:
case Expr::CXXFunctionalCastExprClass:
@@ -599,10 +714,20 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
case Expr::CXXDynamicCastExprClass:
case Expr::CXXReinterpretCastExprClass:
case Expr::CXXConstCastExprClass:
+ case Expr::ObjCBridgedCastExprClass:
return EmitCastLValue(cast<CastExpr>(E));
+
+ case Expr::MaterializeTemporaryExprClass:
+ return EmitMaterializeTemporaryExpr(cast<MaterializeTemporaryExpr>(E));
}
}
+llvm::Value *CodeGenFunction::EmitLoadOfScalar(LValue lvalue) {
+ return EmitLoadOfScalar(lvalue.getAddress(), lvalue.isVolatile(),
+ lvalue.getAlignment(), lvalue.getType(),
+ lvalue.getTBAAInfo());
+}
+
llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile,
unsigned Alignment, QualType Ty,
llvm::MDNode *TBAAInfo) {
@@ -651,6 +776,7 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, llvm::Value *Addr,
QualType Ty,
llvm::MDNode *TBAAInfo) {
Value = EmitToMemory(Value, Ty);
+
llvm::StoreInst *Store = Builder.CreateStore(Value, Addr, Volatile);
if (Alignment)
Store->setAlignment(Alignment);
@@ -658,29 +784,30 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, llvm::Value *Addr,
CGM.DecorateInstruction(Store, TBAAInfo);
}
+void CodeGenFunction::EmitStoreOfScalar(llvm::Value *value, LValue lvalue) {
+ EmitStoreOfScalar(value, lvalue.getAddress(), lvalue.isVolatile(),
+ lvalue.getAlignment(), lvalue.getType(),
+ lvalue.getTBAAInfo());
+}
+
/// EmitLoadOfLValue - Given an expression that represents a value lvalue, this
/// method emits the address of the lvalue, then loads the result as an rvalue,
/// returning the rvalue.
-RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, QualType ExprType) {
+RValue CodeGenFunction::EmitLoadOfLValue(LValue LV) {
if (LV.isObjCWeak()) {
// load of a __weak object.
llvm::Value *AddrWeakObj = LV.getAddress();
return RValue::get(CGM.getObjCRuntime().EmitObjCWeakRead(*this,
AddrWeakObj));
}
+ if (LV.getQuals().getObjCLifetime() == Qualifiers::OCL_Weak)
+ return RValue::get(EmitARCLoadWeak(LV.getAddress()));
if (LV.isSimple()) {
- llvm::Value *Ptr = LV.getAddress();
-
- // Functions are l-values that don't require loading.
- if (ExprType->isFunctionType())
- return RValue::get(Ptr);
+ assert(!LV.getType()->isFunctionType());
// Everything needs a load.
- return RValue::get(EmitLoadOfScalar(Ptr, LV.isVolatileQualified(),
- LV.getAlignment(), ExprType,
- LV.getTBAAInfo()));
-
+ return RValue::get(EmitLoadOfScalar(LV));
}
if (LV.isVectorElt()) {
@@ -693,21 +820,20 @@ RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, QualType ExprType) {
// If this is a reference to a subset of the elements of a vector, either
// shuffle the input or extract/insert them as appropriate.
if (LV.isExtVectorElt())
- return EmitLoadOfExtVectorElementLValue(LV, ExprType);
+ return EmitLoadOfExtVectorElementLValue(LV);
if (LV.isBitField())
- return EmitLoadOfBitfieldLValue(LV, ExprType);
+ return EmitLoadOfBitfieldLValue(LV);
assert(LV.isPropertyRef() && "Unknown LValue type!");
return EmitLoadOfPropertyRefLValue(LV);
}
-RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV,
- QualType ExprType) {
+RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV) {
const CGBitFieldInfo &Info = LV.getBitFieldInfo();
// Get the output type.
- const llvm::Type *ResLTy = ConvertType(ExprType);
+ const llvm::Type *ResLTy = ConvertType(LV.getType());
unsigned ResSizeInBits = CGM.getTargetData().getTypeSizeInBits(ResLTy);
// Compute the result as an OR of all of the individual component accesses.
@@ -733,7 +859,7 @@ RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV,
// Cast to the access type.
const llvm::Type *PTy = llvm::Type::getIntNPtrTy(getLLVMContext(),
AI.AccessWidth,
- CGM.getContext().getTargetAddressSpace(ExprType));
+ CGM.getContext().getTargetAddressSpace(LV.getType()));
Ptr = Builder.CreateBitCast(Ptr, PTy);
// Perform the load.
@@ -777,8 +903,7 @@ RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV,
// If this is a reference to a subset of the elements of a vector, create an
// appropriate shufflevector.
-RValue CodeGenFunction::EmitLoadOfExtVectorElementLValue(LValue LV,
- QualType ExprType) {
+RValue CodeGenFunction::EmitLoadOfExtVectorElementLValue(LValue LV) {
llvm::Value *Vec = Builder.CreateLoad(LV.getExtVectorAddr(),
LV.isVolatileQualified(), "tmp");
@@ -786,7 +911,7 @@ RValue CodeGenFunction::EmitLoadOfExtVectorElementLValue(LValue LV,
// If the result of the expression is a non-vector type, we must be extracting
// a single element. Just codegen as an extractelement.
- const VectorType *ExprVT = ExprType->getAs<VectorType>();
+ const VectorType *ExprVT = LV.getType()->getAs<VectorType>();
if (!ExprVT) {
unsigned InIdx = getAccessedFieldNo(0, Elts);
llvm::Value *Elt = llvm::ConstantInt::get(Int32Ty, InIdx);
@@ -813,8 +938,7 @@ RValue CodeGenFunction::EmitLoadOfExtVectorElementLValue(LValue LV,
/// EmitStoreThroughLValue - Store the specified rvalue into the specified
/// lvalue, where both are guaranteed to the have the same type, and that type
/// is 'Ty'.
-void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst,
- QualType Ty) {
+void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst) {
if (!Dst.isSimple()) {
if (Dst.isVectorElt()) {
// Read/modify/write the vector, inserting the new element.
@@ -829,15 +953,41 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst,
// If this is an update of extended vector elements, insert them as
// appropriate.
if (Dst.isExtVectorElt())
- return EmitStoreThroughExtVectorComponentLValue(Src, Dst, Ty);
+ return EmitStoreThroughExtVectorComponentLValue(Src, Dst);
if (Dst.isBitField())
- return EmitStoreThroughBitfieldLValue(Src, Dst, Ty);
+ return EmitStoreThroughBitfieldLValue(Src, Dst);
assert(Dst.isPropertyRef() && "Unknown LValue type");
return EmitStoreThroughPropertyRefLValue(Src, Dst);
}
+ // There's special magic for assigning into an ARC-qualified l-value.
+ if (Qualifiers::ObjCLifetime Lifetime = Dst.getQuals().getObjCLifetime()) {
+ switch (Lifetime) {
+ case Qualifiers::OCL_None:
+ llvm_unreachable("present but none");
+
+ case Qualifiers::OCL_ExplicitNone:
+ // nothing special
+ break;
+
+ case Qualifiers::OCL_Strong:
+ EmitARCStoreStrong(Dst, Src.getScalarVal(), /*ignore*/ true);
+ return;
+
+ case Qualifiers::OCL_Weak:
+ EmitARCStoreWeak(Dst.getAddress(), Src.getScalarVal(), /*ignore*/ true);
+ return;
+
+ case Qualifiers::OCL_Autoreleasing:
+ Src = RValue::get(EmitObjCExtendObjectLifetime(Dst.getType(),
+ Src.getScalarVal()));
+ // fall into the normal path
+ break;
+ }
+ }
+
if (Dst.isObjCWeak() && !Dst.isNonGC()) {
// load of a __weak object.
llvm::Value *LvalueDst = Dst.getAddress();
@@ -871,24 +1021,21 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst,
}
assert(Src.isScalar() && "Can't emit an agg store with this method");
- EmitStoreOfScalar(Src.getScalarVal(), Dst.getAddress(),
- Dst.isVolatileQualified(), Dst.getAlignment(), Ty,
- Dst.getTBAAInfo());
+ EmitStoreOfScalar(Src.getScalarVal(), Dst);
}
void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst,
- QualType Ty,
llvm::Value **Result) {
const CGBitFieldInfo &Info = Dst.getBitFieldInfo();
// Get the output type.
- const llvm::Type *ResLTy = ConvertTypeForMem(Ty);
+ const llvm::Type *ResLTy = ConvertTypeForMem(Dst.getType());
unsigned ResSizeInBits = CGM.getTargetData().getTypeSizeInBits(ResLTy);
// Get the source value, truncated to the width of the bit-field.
llvm::Value *SrcVal = Src.getScalarVal();
- if (Ty->isBooleanType())
+ if (Dst.getType()->isBooleanType())
SrcVal = Builder.CreateIntCast(SrcVal, ResLTy, /*IsSigned=*/false);
SrcVal = Builder.CreateAnd(SrcVal, llvm::APInt::getLowBitsSet(ResSizeInBits,
@@ -983,8 +1130,7 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst,
}
void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src,
- LValue Dst,
- QualType Ty) {
+ LValue Dst) {
// This access turns into a read/modify/write of the vector. Load the input
// value now.
llvm::Value *Vec = Builder.CreateLoad(Dst.getExtVectorAddr(),
@@ -993,7 +1139,7 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src,
llvm::Value *SrcVal = Src.getScalarVal();
- if (const VectorType *VTy = Ty->getAs<VectorType>()) {
+ if (const VectorType *VTy = Dst.getType()->getAs<VectorType>()) {
unsigned NumSrcElts = VTy->getNumElements();
unsigned NumDstElts =
cast<llvm::VectorType>(Vec->getType())->getNumElements();
@@ -1113,7 +1259,12 @@ static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E,
setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV);
return;
}
-
+
+ if (const ObjCBridgedCastExpr *Exp = dyn_cast<ObjCBridgedCastExpr>(E)) {
+ setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV);
+ return;
+ }
+
if (const ArraySubscriptExpr *Exp = dyn_cast<ArraySubscriptExpr>(E)) {
setObjCGCLValueClass(Ctx, Exp->getBase(), LV);
if (LV.isObjCIvar() && !LV.isObjCArray())
@@ -1136,6 +1287,14 @@ static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E,
}
}
+static llvm::Value *
+EmitBitCastOfLValueToProperType(CodeGenFunction &CGF,
+ llvm::Value *V, llvm::Type *IRType,
+ llvm::StringRef Name = llvm::StringRef()) {
+ unsigned AS = cast<llvm::PointerType>(V->getType())->getAddressSpace();
+ return CGF.Builder.CreateBitCast(V, IRType->getPointerTo(AS), Name);
+}
+
static LValue EmitGlobalVarDeclLValue(CodeGenFunction &CGF,
const Expr *E, const VarDecl *VD) {
assert((VD->hasExternalStorage() || VD->isFileVarDecl()) &&
@@ -1144,6 +1303,10 @@ static LValue EmitGlobalVarDeclLValue(CodeGenFunction &CGF,
llvm::Value *V = CGF.CGM.GetAddrOfGlobalVar(VD);
if (VD->getType()->isReferenceType())
V = CGF.Builder.CreateLoad(V, "tmp");
+
+ V = EmitBitCastOfLValueToProperType(CGF, V,
+ CGF.getTypes().ConvertTypeForMem(E->getType()));
+
unsigned Alignment = CGF.getContext().getDeclAlign(VD).getQuantity();
LValue LV = CGF.MakeAddrLValue(V, E->getType(), Alignment);
setObjCGCLValueClass(CGF.getContext(), E, LV);
@@ -1151,7 +1314,7 @@ static LValue EmitGlobalVarDeclLValue(CodeGenFunction &CGF,
}
static LValue EmitFunctionDeclLValue(CodeGenFunction &CGF,
- const Expr *E, const FunctionDecl *FD) {
+ const Expr *E, const FunctionDecl *FD) {
llvm::Value *V = CGF.CGM.GetAddrOfFunction(FD);
if (!FD->hasPrototype()) {
if (const FunctionProtoType *Proto =
@@ -1200,6 +1363,9 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
if (VD->getType()->isReferenceType())
V = Builder.CreateLoad(V, "tmp");
+ V = EmitBitCastOfLValueToProperType(*this, V,
+ getTypes().ConvertTypeForMem(E->getType()));
+
LValue LV = MakeAddrLValue(V, E->getType(), Alignment);
if (NonGCable) {
LV.getQuals().removeObjCGCAttr();
@@ -1359,7 +1525,7 @@ llvm::BasicBlock *CodeGenFunction::getTrapBB() {
TrapBB = createBasicBlock("trap");
EmitBlock(TrapBB);
- llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::trap, 0, 0);
+ llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::trap);
llvm::CallInst *TrapCall = Builder.CreateCall(F);
TrapCall->setDoesNotReturn();
TrapCall->setDoesNotThrow();
@@ -1400,7 +1566,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) {
assert(LHS.isSimple() && "Can only subscript lvalue vectors here!");
Idx = Builder.CreateIntCast(Idx, Int32Ty, IdxSigned, "vidx");
return LValue::MakeVectorElt(LHS.getAddress(), Idx,
- E->getBase()->getType().getCVRQualifiers());
+ E->getBase()->getType());
}
// Extend or truncate the index type to 32 or 64-bits.
@@ -1430,21 +1596,27 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) {
// size is a VLA or Objective-C interface.
llvm::Value *Address = 0;
unsigned ArrayAlignment = 0;
- if (const VariableArrayType *VAT =
+ if (const VariableArrayType *vla =
getContext().getAsVariableArrayType(E->getType())) {
- llvm::Value *VLASize = GetVLASize(VAT);
-
- Idx = Builder.CreateMul(Idx, VLASize);
-
- // The base must be a pointer, which is not an aggregate. Emit it.
- llvm::Value *Base = EmitScalarExpr(E->getBase());
-
- Address = EmitCastToVoidPtr(Base);
- if (getContext().getLangOptions().isSignedOverflowDefined())
+ // The base must be a pointer, which is not an aggregate. Emit
+ // it. It needs to be emitted first in case it's what captures
+ // the VLA bounds.
+ Address = EmitScalarExpr(E->getBase());
+
+ // The element count here is the total number of non-VLA elements.
+ llvm::Value *numElements = getVLASize(vla).first;
+
+ // Effectively, the multiply by the VLA size is part of the GEP.
+ // GEP indexes are signed, and scaling an index isn't permitted to
+ // signed-overflow, so we use the same semantics for our explicit
+ // multiply. We suppress this if overflow is not undefined behavior.
+ if (getLangOptions().isSignedOverflowDefined()) {
+ Idx = Builder.CreateMul(Idx, numElements);
Address = Builder.CreateGEP(Address, Idx, "arrayidx");
- else
+ } else {
+ Idx = Builder.CreateNSWMul(Idx, numElements);
Address = Builder.CreateInBoundsGEP(Address, Idx, "arrayidx");
- Address = Builder.CreateBitCast(Address, Base->getType());
+ }
} else if (const ObjCObjectType *OIT = E->getType()->getAs<ObjCObjectType>()){
// Indexing over an interface, as in "NSString *P; P[4];"
llvm::Value *InterfaceSize =
@@ -1539,7 +1711,7 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) {
Base = EmitLValue(E->getBase());
} else {
// Otherwise, the base is a normal rvalue (as in (V+V).x), emit it as such.
- assert(E->getBase()->getType()->getAs<VectorType>() &&
+ assert(E->getBase()->getType()->isVectorType() &&
"Result must be a vector");
llvm::Value *Vec = EmitScalarExpr(E->getBase());
@@ -1548,6 +1720,9 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) {
Builder.CreateStore(Vec, VecMem);
Base = MakeAddrLValue(VecMem, E->getBase()->getType());
}
+
+ QualType type =
+ E->getType().withCVRQualifiers(Base.getQuals().getCVRQualifiers());
// Encode the element access list into a vector of unsigned indices.
llvm::SmallVector<unsigned, 4> Indices;
@@ -1555,8 +1730,7 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) {
if (Base.isSimple()) {
llvm::Constant *CV = GenerateConstantVector(getLLVMContext(), Indices);
- return LValue::MakeExtVectorElt(Base.getAddress(), CV,
- Base.getVRQualifiers());
+ return LValue::MakeExtVectorElt(Base.getAddress(), CV, type);
}
assert(Base.isExtVectorElt() && "Can only subscript lvalue vec elts here!");
@@ -1570,8 +1744,7 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) {
CElts.push_back(cast<llvm::Constant>(BaseElts->getOperand(Indices[i])));
}
llvm::Constant *CV = llvm::ConstantVector::get(CElts);
- return LValue::MakeExtVectorElt(Base.getExtVectorAddr(), CV,
- Base.getVRQualifiers());
+ return LValue::MakeExtVectorElt(Base.getExtVectorAddr(), CV, type);
}
LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) {
@@ -1622,7 +1795,7 @@ LValue CodeGenFunction::EmitLValueForBitfield(llvm::Value *BaseValue,
CGM.getTypes().getCGRecordLayout(Field->getParent());
const CGBitFieldInfo &Info = RL.getBitFieldInfo(Field);
return LValue::MakeBitfield(BaseValue, Info,
- Field->getType().getCVRQualifiers()|CVRQualifiers);
+ Field->getType().withCVRQualifiers(CVRQualifiers));
}
/// EmitLValueForAnonRecordField - Given that the field is a member of
@@ -1656,20 +1829,14 @@ LValue CodeGenFunction::EmitLValueForField(llvm::Value *baseAddr,
bool mayAlias = rec->hasAttr<MayAliasAttr>();
- llvm::Value *addr;
+ llvm::Value *addr = baseAddr;
if (rec->isUnion()) {
- // For unions, we just cast to the appropriate type.
+ // For unions, there is no pointer adjustment.
assert(!type->isReferenceType() && "union has reference member");
-
- const llvm::Type *llvmType = CGM.getTypes().ConvertTypeForMem(type);
- unsigned AS =
- cast<llvm::PointerType>(baseAddr->getType())->getAddressSpace();
- addr = Builder.CreateBitCast(baseAddr, llvmType->getPointerTo(AS),
- field->getName());
} else {
// For structs, we GEP to the field that the record layout suggests.
unsigned idx = CGM.getTypes().getCGRecordLayout(rec).getLLVMFieldNo(field);
- addr = Builder.CreateStructGEP(baseAddr, idx, field->getName());
+ addr = Builder.CreateStructGEP(addr, idx, field->getName());
// If this is a reference field, load the reference right now.
if (const ReferenceType *refType = type->getAs<ReferenceType>()) {
@@ -1691,6 +1858,14 @@ LValue CodeGenFunction::EmitLValueForField(llvm::Value *baseAddr,
cvr = 0; // qualifiers don't recursively apply to referencee
}
}
+
+ // Make sure that the address is pointing to the right type. This is critical
+ // for both unions and structs. A union needs a bitcast, a struct element
+ // will need a bitcast if the LLVM type laid out doesn't match the desired
+ // type.
+ addr = EmitBitCastOfLValueToProperType(*this, addr,
+ CGM.getTypes().ConvertTypeForMem(type),
+ field->getName());
unsigned alignment = getContext().getDeclAlign(field).getQuantity();
LValue LV = MakeAddrLValue(addr, type, alignment);
@@ -1722,9 +1897,17 @@ CodeGenFunction::EmitLValueForFieldInitialization(llvm::Value *BaseValue,
CGM.getTypes().getCGRecordLayout(Field->getParent());
unsigned idx = RL.getLLVMFieldNo(Field);
llvm::Value *V = Builder.CreateStructGEP(BaseValue, idx, "tmp");
-
assert(!FieldType.getObjCGCAttr() && "fields cannot have GC attrs");
+
+ // Make sure that the address is pointing to the right type. This is critical
+ // for both unions and structs. A union needs a bitcast, a struct element
+ // will need a bitcast if the LLVM type laid out doesn't match the desired
+ // type.
+ const llvm::Type *llvmType = ConvertTypeForMem(FieldType);
+ unsigned AS = cast<llvm::PointerType>(V->getType())->getAddressSpace();
+ V = Builder.CreateBitCast(V, llvmType->getPointerTo(AS));
+
unsigned Alignment = getContext().getDeclAlign(Field).getQuantity();
return MakeAddrLValue(V, FieldType, Alignment);
}
@@ -1734,7 +1917,8 @@ LValue CodeGenFunction::EmitCompoundLiteralLValue(const CompoundLiteralExpr *E){
const Expr *InitExpr = E->getInitializer();
LValue Result = MakeAddrLValue(DeclPtr, E->getType());
- EmitAnyExprToMem(InitExpr, DeclPtr, /*Volatile*/ false, /*Init*/ true);
+ EmitAnyExprToMem(InitExpr, DeclPtr, E->getType().getQualifiers(),
+ /*Init*/ true);
return Result;
}
@@ -1863,13 +2047,16 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
case CK_DerivedToBaseMemberPointer:
case CK_BaseToDerivedMemberPointer:
case CK_MemberPointerToBoolean:
- case CK_AnyPointerToBlockPointerCast: {
+ case CK_AnyPointerToBlockPointerCast:
+ case CK_ObjCProduceObject:
+ case CK_ObjCConsumeObject:
+ case CK_ObjCReclaimReturnedObject: {
// These casts only produce lvalues when we're binding a reference to a
// temporary realized from a (converted) pure rvalue. Emit the expression
// as a value, copy it into a temporary, and return an lvalue referring to
// that temporary.
llvm::Value *V = CreateMemTemp(E->getType(), "ref.temp");
- EmitAnyExprToMem(E, V, false, false);
+ EmitAnyExprToMem(E, V, E->getType().getQualifiers(), false);
return MakeAddrLValue(V, E->getType());
}
@@ -1954,11 +2141,18 @@ LValue CodeGenFunction::EmitOpaqueValueLValue(const OpaqueValueExpr *e) {
return getOpaqueLValueMapping(e);
}
+LValue CodeGenFunction::EmitMaterializeTemporaryExpr(
+ const MaterializeTemporaryExpr *E) {
+ RValue RV = EmitReferenceBindingToExpr(E->GetTemporaryExpr(),
+ /*InitializedDecl=*/0);
+ return MakeAddrLValue(RV.getScalarVal(), E->getType());
+}
+
+
//===--------------------------------------------------------------------===//
// Expression Emission
//===--------------------------------------------------------------------===//
-
RValue CodeGenFunction::EmitCallExpr(const CallExpr *E,
ReturnValueSlot ReturnValue) {
if (CGDebugInfo *DI = getDebugInfo()) {
@@ -1988,13 +2182,57 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E,
if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(TargetDecl))
return EmitCXXOperatorMemberCallExpr(CE, MD, ReturnValue);
- if (isa<CXXPseudoDestructorExpr>(E->getCallee()->IgnoreParens())) {
- // C++ [expr.pseudo]p1:
- // The result shall only be used as the operand for the function call
- // operator (), and the result of such a call has type void. The only
- // effect is the evaluation of the postfix-expression before the dot or
- // arrow.
- EmitScalarExpr(E->getCallee());
+ if (const CXXPseudoDestructorExpr *PseudoDtor
+ = dyn_cast<CXXPseudoDestructorExpr>(E->getCallee()->IgnoreParens())) {
+ QualType DestroyedType = PseudoDtor->getDestroyedType();
+ if (getContext().getLangOptions().ObjCAutoRefCount &&
+ DestroyedType->isObjCLifetimeType() &&
+ (DestroyedType.getObjCLifetime() == Qualifiers::OCL_Strong ||
+ DestroyedType.getObjCLifetime() == Qualifiers::OCL_Weak)) {
+ // Automatic Reference Counting:
+ // If the pseudo-expression names a retainable object with weak or
+ // strong lifetime, the object shall be released.
+ Expr *BaseExpr = PseudoDtor->getBase();
+ llvm::Value *BaseValue = NULL;
+ Qualifiers BaseQuals;
+
+ // If this is s.x, emit s as an lvalue. If it is s->x, emit s as a scalar.
+ if (PseudoDtor->isArrow()) {
+ BaseValue = EmitScalarExpr(BaseExpr);
+ const PointerType *PTy = BaseExpr->getType()->getAs<PointerType>();
+ BaseQuals = PTy->getPointeeType().getQualifiers();
+ } else {
+ LValue BaseLV = EmitLValue(BaseExpr);
+ BaseValue = BaseLV.getAddress();
+ QualType BaseTy = BaseExpr->getType();
+ BaseQuals = BaseTy.getQualifiers();
+ }
+
+ switch (PseudoDtor->getDestroyedType().getObjCLifetime()) {
+ case Qualifiers::OCL_None:
+ case Qualifiers::OCL_ExplicitNone:
+ case Qualifiers::OCL_Autoreleasing:
+ break;
+
+ case Qualifiers::OCL_Strong:
+ EmitARCRelease(Builder.CreateLoad(BaseValue,
+ PseudoDtor->getDestroyedType().isVolatileQualified()),
+ /*precise*/ true);
+ break;
+
+ case Qualifiers::OCL_Weak:
+ EmitARCDestroyWeak(BaseValue);
+ break;
+ }
+ } else {
+ // C++ [expr.pseudo]p1:
+ // The result shall only be used as the operand for the function call
+ // operator (), and the result of such a call has type void. The only
+ // effect is the evaluation of the postfix-expression before the dot or
+ // arrow.
+ EmitScalarExpr(E->getCallee());
+ }
+
return RValue::get(0);
}
@@ -2016,12 +2254,28 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) {
return EmitPointerToDataMemberBinaryExpr(E);
assert(E->getOpcode() == BO_Assign && "unexpected binary l-value");
+
+ // Note that in all of these cases, __block variables need the RHS
+ // evaluated first just in case the variable gets moved by the RHS.
if (!hasAggregateLLVMType(E->getType())) {
- // __block variables need the RHS evaluated first.
+ switch (E->getLHS()->getType().getObjCLifetime()) {
+ case Qualifiers::OCL_Strong:
+ return EmitARCStoreStrong(E, /*ignored*/ false).first;
+
+ case Qualifiers::OCL_Autoreleasing:
+ return EmitARCStoreAutoreleasing(E).first;
+
+ // No reason to do any of these differently.
+ case Qualifiers::OCL_None:
+ case Qualifiers::OCL_ExplicitNone:
+ case Qualifiers::OCL_Weak:
+ break;
+ }
+
RValue RV = EmitAnyExpr(E->getRHS());
LValue LV = EmitLValue(E->getLHS());
- EmitStoreThroughLValue(RV, LV, E->getType());
+ EmitStoreThroughLValue(RV, LV);
return LV;
}
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index d8da642a6b38..915ffd6034e2 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -85,15 +85,16 @@ public:
Visit(GE->getResultExpr());
}
void VisitUnaryExtension(UnaryOperator *E) { Visit(E->getSubExpr()); }
+ void VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *E) {
+ return Visit(E->getReplacement());
+ }
// l-values.
void VisitDeclRefExpr(DeclRefExpr *DRE) { EmitAggLoadOfLValue(DRE); }
void VisitMemberExpr(MemberExpr *ME) { EmitAggLoadOfLValue(ME); }
void VisitUnaryDeref(UnaryOperator *E) { EmitAggLoadOfLValue(E); }
void VisitStringLiteral(StringLiteral *E) { EmitAggLoadOfLValue(E); }
- void VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
- EmitAggLoadOfLValue(E);
- }
+ void VisitCompoundLiteralExpr(CompoundLiteralExpr *E);
void VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
EmitAggLoadOfLValue(E);
}
@@ -131,13 +132,13 @@ public:
void VisitExprWithCleanups(ExprWithCleanups *E);
void VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E);
void VisitCXXTypeidExpr(CXXTypeidExpr *E) { EmitAggLoadOfLValue(E); }
-
+ void VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E);
void VisitOpaqueValueExpr(OpaqueValueExpr *E);
void VisitVAArgExpr(VAArgExpr *E);
- void EmitInitializationToLValue(Expr *E, LValue Address, QualType T);
- void EmitNullInitializationToLValue(LValue Address, QualType T);
+ void EmitInitializationToLValue(Expr *E, LValue Address);
+ void EmitNullInitializationToLValue(LValue Address);
// case Expr::ChooseExprClass:
void VisitCXXThrowExpr(const CXXThrowExpr *E) { CGF.EmitCXXThrowExpr(E); }
};
@@ -243,10 +244,31 @@ void AggExprEmitter::EmitFinalDestCopy(const Expr *E, LValue Src, bool Ignore) {
// Visitor Methods
//===----------------------------------------------------------------------===//
+void AggExprEmitter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E){
+ Visit(E->GetTemporaryExpr());
+}
+
void AggExprEmitter::VisitOpaqueValueExpr(OpaqueValueExpr *e) {
EmitFinalDestCopy(e, CGF.getOpaqueLValueMapping(e));
}
+void
+AggExprEmitter::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
+ if (E->getType().isPODType(CGF.getContext())) {
+ // For a POD type, just emit a load of the lvalue + a copy, because our
+ // compound literal might alias the destination.
+ // FIXME: This is a band-aid; the real problem appears to be in our handling
+ // of assignments, where we store directly into the LHS without checking
+ // whether anything in the RHS aliases.
+ EmitAggLoadOfLValue(E);
+ return;
+ }
+
+ AggValueSlot Slot = EnsureSlot(E->getType());
+ CGF.EmitAggExpr(E->getInitializer(), Slot);
+}
+
+
void AggExprEmitter::VisitCastExpr(CastExpr *E) {
switch (E->getCastKind()) {
case CK_Dynamic: {
@@ -271,8 +293,8 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
QualType PtrTy = CGF.getContext().getPointerType(Ty);
llvm::Value *CastPtr = Builder.CreateBitCast(Dest.getAddr(),
CGF.ConvertType(PtrTy));
- EmitInitializationToLValue(E->getSubExpr(), CGF.MakeAddrLValue(CastPtr, Ty),
- Ty);
+ EmitInitializationToLValue(E->getSubExpr(),
+ CGF.MakeAddrLValue(CastPtr, Ty));
break;
}
@@ -339,6 +361,9 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
case CK_IntegralComplexToBoolean:
case CK_IntegralComplexCast:
case CK_IntegralComplexToFloatingComplex:
+ case CK_ObjCProduceObject:
+ case CK_ObjCConsumeObject:
+ case CK_ObjCReclaimReturnedObject:
llvm_unreachable("cast kind invalid for aggregate types");
}
}
@@ -519,13 +544,13 @@ void AggExprEmitter::VisitExprWithCleanups(ExprWithCleanups *E) {
void AggExprEmitter::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E) {
QualType T = E->getType();
AggValueSlot Slot = EnsureSlot(T);
- EmitNullInitializationToLValue(CGF.MakeAddrLValue(Slot.getAddr(), T), T);
+ EmitNullInitializationToLValue(CGF.MakeAddrLValue(Slot.getAddr(), T));
}
void AggExprEmitter::VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) {
QualType T = E->getType();
AggValueSlot Slot = EnsureSlot(T);
- EmitNullInitializationToLValue(CGF.MakeAddrLValue(Slot.getAddr(), T), T);
+ EmitNullInitializationToLValue(CGF.MakeAddrLValue(Slot.getAddr(), T));
}
/// isSimpleZero - If emitting this value will obviously just cause a store of
@@ -557,41 +582,46 @@ static bool isSimpleZero(const Expr *E, CodeGenFunction &CGF) {
void
-AggExprEmitter::EmitInitializationToLValue(Expr* E, LValue LV, QualType T) {
+AggExprEmitter::EmitInitializationToLValue(Expr* E, LValue LV) {
+ QualType type = LV.getType();
// FIXME: Ignore result?
// FIXME: Are initializers affected by volatile?
if (Dest.isZeroed() && isSimpleZero(E, CGF)) {
// Storing "i32 0" to a zero'd memory location is a noop.
} else if (isa<ImplicitValueInitExpr>(E)) {
- EmitNullInitializationToLValue(LV, T);
- } else if (T->isReferenceType()) {
+ EmitNullInitializationToLValue(LV);
+ } else if (type->isReferenceType()) {
RValue RV = CGF.EmitReferenceBindingToExpr(E, /*InitializedDecl=*/0);
- CGF.EmitStoreThroughLValue(RV, LV, T);
- } else if (T->isAnyComplexType()) {
+ CGF.EmitStoreThroughLValue(RV, LV);
+ } else if (type->isAnyComplexType()) {
CGF.EmitComplexExprIntoAddr(E, LV.getAddress(), false);
- } else if (CGF.hasAggregateLLVMType(T)) {
- CGF.EmitAggExpr(E, AggValueSlot::forAddr(LV.getAddress(), false, true,
- false, Dest.isZeroed()));
+ } else if (CGF.hasAggregateLLVMType(type)) {
+ CGF.EmitAggExpr(E, AggValueSlot::forLValue(LV, true, false,
+ Dest.isZeroed()));
+ } else if (LV.isSimple()) {
+ CGF.EmitScalarInit(E, /*D=*/0, LV, /*Captured=*/false);
} else {
- CGF.EmitStoreThroughLValue(RValue::get(CGF.EmitScalarExpr(E)), LV, T);
+ CGF.EmitStoreThroughLValue(RValue::get(CGF.EmitScalarExpr(E)), LV);
}
}
-void AggExprEmitter::EmitNullInitializationToLValue(LValue LV, QualType T) {
+void AggExprEmitter::EmitNullInitializationToLValue(LValue lv) {
+ QualType type = lv.getType();
+
// If the destination slot is already zeroed out before the aggregate is
// copied into it, we don't have to emit any zeros here.
- if (Dest.isZeroed() && CGF.getTypes().isZeroInitializable(T))
+ if (Dest.isZeroed() && CGF.getTypes().isZeroInitializable(type))
return;
- if (!CGF.hasAggregateLLVMType(T)) {
+ if (!CGF.hasAggregateLLVMType(type)) {
// For non-aggregates, we can store zero
- llvm::Value *Null = llvm::Constant::getNullValue(CGF.ConvertType(T));
- CGF.EmitStoreThroughLValue(RValue::get(Null), LV, T);
+ llvm::Value *null = llvm::Constant::getNullValue(CGF.ConvertType(type));
+ CGF.EmitStoreThroughLValue(RValue::get(null), lv);
} else {
// There's a potential optimization opportunity in combining
// memsets; that would be easy for arrays, but relatively
// difficult for structures with the current code.
- CGF.EmitNullInitialization(LV.getAddress(), T);
+ CGF.EmitNullInitialization(lv.getAddress(), lv.getType());
}
}
@@ -634,45 +664,135 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
}
uint64_t NumArrayElements = AType->getNumElements();
- QualType ElementType = CGF.getContext().getCanonicalType(E->getType());
- ElementType = CGF.getContext().getAsArrayType(ElementType)->getElementType();
-
- bool hasNonTrivialCXXConstructor = false;
- if (CGF.getContext().getLangOptions().CPlusPlus)
- if (const RecordType *RT = CGF.getContext()
- .getBaseElementType(ElementType)->getAs<RecordType>()) {
- const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- hasNonTrivialCXXConstructor = !RD->hasTrivialDefaultConstructor();
+ assert(NumInitElements <= NumArrayElements);
+
+ QualType elementType = E->getType().getCanonicalType();
+ elementType = CGF.getContext().getQualifiedType(
+ cast<ArrayType>(elementType)->getElementType(),
+ elementType.getQualifiers() + Dest.getQualifiers());
+
+ // DestPtr is an array*. Construct an elementType* by drilling
+ // down a level.
+ llvm::Value *zero = llvm::ConstantInt::get(CGF.SizeTy, 0);
+ llvm::Value *indices[] = { zero, zero };
+ llvm::Value *begin =
+ Builder.CreateInBoundsGEP(DestPtr, indices, indices+2, "arrayinit.begin");
+
+ // Exception safety requires us to destroy all the
+ // already-constructed members if an initializer throws.
+ // For that, we'll need an EH cleanup.
+ QualType::DestructionKind dtorKind = elementType.isDestructedType();
+ llvm::AllocaInst *endOfInit = 0;
+ EHScopeStack::stable_iterator cleanup;
+ if (CGF.needsEHCleanup(dtorKind)) {
+ // In principle we could tell the cleanup where we are more
+ // directly, but the control flow can get so varied here that it
+ // would actually be quite complex. Therefore we go through an
+ // alloca.
+ endOfInit = CGF.CreateTempAlloca(begin->getType(),
+ "arrayinit.endOfInit");
+ Builder.CreateStore(begin, endOfInit);
+ CGF.pushIrregularPartialArrayCleanup(begin, endOfInit, elementType,
+ CGF.getDestroyer(dtorKind));
+ cleanup = CGF.EHStack.stable_begin();
+
+ // Otherwise, remember that we didn't need a cleanup.
+ } else {
+ dtorKind = QualType::DK_none;
+ }
+
+ llvm::Value *one = llvm::ConstantInt::get(CGF.SizeTy, 1);
+
+ // The 'current element to initialize'. The invariants on this
+ // variable are complicated. Essentially, after each iteration of
+ // the loop, it points to the last initialized element, except
+ // that it points to the beginning of the array before any
+ // elements have been initialized.
+ llvm::Value *element = begin;
+
+ // Emit the explicit initializers.
+ for (uint64_t i = 0; i != NumInitElements; ++i) {
+ // Advance to the next element.
+ if (i > 0) {
+ element = Builder.CreateInBoundsGEP(element, one, "arrayinit.element");
+
+ // Tell the cleanup that it needs to destroy up to this
+ // element. TODO: some of these stores can be trivially
+ // observed to be unnecessary.
+ if (endOfInit) Builder.CreateStore(element, endOfInit);
}
- // FIXME: were we intentionally ignoring address spaces and GC attributes?
+ LValue elementLV = CGF.MakeAddrLValue(element, elementType);
+ EmitInitializationToLValue(E->getInit(i), elementLV);
+ }
- for (uint64_t i = 0; i != NumArrayElements; ++i) {
- // If we're done emitting initializers and the destination is known-zeroed
- // then we're done.
- if (i == NumInitElements &&
- Dest.isZeroed() &&
- CGF.getTypes().isZeroInitializable(ElementType) &&
- !hasNonTrivialCXXConstructor)
- break;
+ // Check whether there's a non-trivial array-fill expression.
+ // Note that this will be a CXXConstructExpr even if the element
+ // type is an array (or array of array, etc.) of class type.
+ Expr *filler = E->getArrayFiller();
+ bool hasTrivialFiller = true;
+ if (CXXConstructExpr *cons = dyn_cast_or_null<CXXConstructExpr>(filler)) {
+ assert(cons->getConstructor()->isDefaultConstructor());
+ hasTrivialFiller = cons->getConstructor()->isTrivial();
+ }
- llvm::Value *NextVal = Builder.CreateStructGEP(DestPtr, i, ".array");
- LValue LV = CGF.MakeAddrLValue(NextVal, ElementType);
-
- if (i < NumInitElements)
- EmitInitializationToLValue(E->getInit(i), LV, ElementType);
- else if (Expr *filler = E->getArrayFiller())
- EmitInitializationToLValue(filler, LV, ElementType);
+ // Any remaining elements need to be zero-initialized, possibly
+ // using the filler expression. We can skip this if the we're
+ // emitting to zeroed memory.
+ if (NumInitElements != NumArrayElements &&
+ !(Dest.isZeroed() && hasTrivialFiller &&
+ CGF.getTypes().isZeroInitializable(elementType))) {
+
+ // Use an actual loop. This is basically
+ // do { *array++ = filler; } while (array != end);
+
+ // Advance to the start of the rest of the array.
+ if (NumInitElements) {
+ element = Builder.CreateInBoundsGEP(element, one, "arrayinit.start");
+ if (endOfInit) Builder.CreateStore(element, endOfInit);
+ }
+
+ // Compute the end of the array.
+ llvm::Value *end = Builder.CreateInBoundsGEP(begin,
+ llvm::ConstantInt::get(CGF.SizeTy, NumArrayElements),
+ "arrayinit.end");
+
+ llvm::BasicBlock *entryBB = Builder.GetInsertBlock();
+ llvm::BasicBlock *bodyBB = CGF.createBasicBlock("arrayinit.body");
+
+ // Jump into the body.
+ CGF.EmitBlock(bodyBB);
+ llvm::PHINode *currentElement =
+ Builder.CreatePHI(element->getType(), 2, "arrayinit.cur");
+ currentElement->addIncoming(element, entryBB);
+
+ // Emit the actual filler expression.
+ LValue elementLV = CGF.MakeAddrLValue(currentElement, elementType);
+ if (filler)
+ EmitInitializationToLValue(filler, elementLV);
else
- EmitNullInitializationToLValue(LV, ElementType);
-
- // If the GEP didn't get used because of a dead zero init or something
- // else, clean it up for -O0 builds and general tidiness.
- if (llvm::GetElementPtrInst *GEP =
- dyn_cast<llvm::GetElementPtrInst>(NextVal))
- if (GEP->use_empty())
- GEP->eraseFromParent();
+ EmitNullInitializationToLValue(elementLV);
+
+ // Move on to the next element.
+ llvm::Value *nextElement =
+ Builder.CreateInBoundsGEP(currentElement, one, "arrayinit.next");
+
+ // Tell the EH cleanup that we finished with the last element.
+ if (endOfInit) Builder.CreateStore(nextElement, endOfInit);
+
+ // Leave the loop if we're done.
+ llvm::Value *done = Builder.CreateICmpEQ(nextElement, end,
+ "arrayinit.done");
+ llvm::BasicBlock *endBB = CGF.createBasicBlock("arrayinit.end");
+ Builder.CreateCondBr(done, endBB, bodyBB);
+ currentElement->addIncoming(nextElement, Builder.GetInsertBlock());
+
+ CGF.EmitBlock(endBB);
}
+
+ // Leave the partial-array cleanup if we entered one.
+ if (dtorKind) CGF.DeactivateCleanupBlock(cleanup);
+
return;
}
@@ -683,9 +803,9 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
// the disadvantage is that the generated code is more difficult for
// the optimizer, especially with bitfields.
unsigned NumInitElements = E->getNumInits();
- RecordDecl *SD = E->getType()->getAs<RecordType>()->getDecl();
+ RecordDecl *record = E->getType()->castAs<RecordType>()->getDecl();
- if (E->getType()->isUnionType()) {
+ if (record->isUnion()) {
// Only initialize one field of a union. The field itself is
// specified by the initializer list.
if (!E->getInitializedFieldInUnion()) {
@@ -694,8 +814,8 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
#ifndef NDEBUG
// Make sure that it's really an empty and not a failure of
// semantic analysis.
- for (RecordDecl::field_iterator Field = SD->field_begin(),
- FieldEnd = SD->field_end();
+ for (RecordDecl::field_iterator Field = record->field_begin(),
+ FieldEnd = record->field_end();
Field != FieldEnd; ++Field)
assert(Field->isUnnamedBitfield() && "Only unnamed bitfields allowed");
#endif
@@ -708,55 +828,81 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
LValue FieldLoc = CGF.EmitLValueForFieldInitialization(DestPtr, Field, 0);
if (NumInitElements) {
// Store the initializer into the field
- EmitInitializationToLValue(E->getInit(0), FieldLoc, Field->getType());
+ EmitInitializationToLValue(E->getInit(0), FieldLoc);
} else {
// Default-initialize to null.
- EmitNullInitializationToLValue(FieldLoc, Field->getType());
+ EmitNullInitializationToLValue(FieldLoc);
}
return;
}
+ // We'll need to enter cleanup scopes in case any of the member
+ // initializers throw an exception.
+ llvm::SmallVector<EHScopeStack::stable_iterator, 16> cleanups;
+
// Here we iterate over the fields; this makes it simpler to both
// default-initialize fields and skip over unnamed fields.
- unsigned CurInitVal = 0;
- for (RecordDecl::field_iterator Field = SD->field_begin(),
- FieldEnd = SD->field_end();
- Field != FieldEnd; ++Field) {
- // We're done once we hit the flexible array member
- if (Field->getType()->isIncompleteArrayType())
+ unsigned curInitIndex = 0;
+ for (RecordDecl::field_iterator field = record->field_begin(),
+ fieldEnd = record->field_end();
+ field != fieldEnd; ++field) {
+ // We're done once we hit the flexible array member.
+ if (field->getType()->isIncompleteArrayType())
break;
- if (Field->isUnnamedBitfield())
+ // Always skip anonymous bitfields.
+ if (field->isUnnamedBitfield())
continue;
- // Don't emit GEP before a noop store of zero.
- if (CurInitVal == NumInitElements && Dest.isZeroed() &&
+ // We're done if we reach the end of the explicit initializers, we
+ // have a zeroed object, and the rest of the fields are
+ // zero-initializable.
+ if (curInitIndex == NumInitElements && Dest.isZeroed() &&
CGF.getTypes().isZeroInitializable(E->getType()))
break;
// FIXME: volatility
- LValue FieldLoc = CGF.EmitLValueForFieldInitialization(DestPtr, *Field, 0);
+ LValue LV = CGF.EmitLValueForFieldInitialization(DestPtr, *field, 0);
// We never generate write-barries for initialized fields.
- FieldLoc.setNonGC(true);
+ LV.setNonGC(true);
- if (CurInitVal < NumInitElements) {
+ if (curInitIndex < NumInitElements) {
// Store the initializer into the field.
- EmitInitializationToLValue(E->getInit(CurInitVal++), FieldLoc,
- Field->getType());
+ EmitInitializationToLValue(E->getInit(curInitIndex++), LV);
} else {
// We're out of initalizers; default-initialize to null
- EmitNullInitializationToLValue(FieldLoc, Field->getType());
+ EmitNullInitializationToLValue(LV);
+ }
+
+ // Push a destructor if necessary.
+ // FIXME: if we have an array of structures, all explicitly
+ // initialized, we can end up pushing a linear number of cleanups.
+ bool pushedCleanup = false;
+ if (QualType::DestructionKind dtorKind
+ = field->getType().isDestructedType()) {
+ assert(LV.isSimple());
+ if (CGF.needsEHCleanup(dtorKind)) {
+ CGF.pushDestroy(EHCleanup, LV.getAddress(), field->getType(),
+ CGF.getDestroyer(dtorKind), false);
+ cleanups.push_back(CGF.EHStack.stable_begin());
+ pushedCleanup = true;
+ }
}
// If the GEP didn't get used because of a dead zero init or something
// else, clean it up for -O0 builds and general tidiness.
- if (FieldLoc.isSimple())
+ if (!pushedCleanup && LV.isSimple())
if (llvm::GetElementPtrInst *GEP =
- dyn_cast<llvm::GetElementPtrInst>(FieldLoc.getAddress()))
+ dyn_cast<llvm::GetElementPtrInst>(LV.getAddress()))
if (GEP->use_empty())
GEP->eraseFromParent();
}
+
+ // Deactivate all the partial cleanups in reverse order, which
+ // generally means popping them.
+ for (unsigned i = cleanups.size(); i != 0; --i)
+ CGF.DeactivateCleanupBlock(cleanups[i-1]);
}
//===----------------------------------------------------------------------===//
@@ -873,8 +1019,6 @@ static void CheckAggExprForMemSetUse(AggValueSlot &Slot, const Expr *E,
///
/// \param IsInitializer - true if this evaluation is initializing an
/// object whose lifetime is already being managed.
-//
-// FIXME: Take Qualifiers object.
void CodeGenFunction::EmitAggExpr(const Expr *E, AggValueSlot Slot,
bool IgnoreResult) {
assert(E && hasAggregateLLVMType(E->getType()) &&
@@ -892,7 +1036,7 @@ LValue CodeGenFunction::EmitAggExprToLValue(const Expr *E) {
assert(hasAggregateLLVMType(E->getType()) && "Invalid argument!");
llvm::Value *Temp = CreateMemTemp(E->getType());
LValue LV = MakeAddrLValue(Temp, E->getType());
- EmitAggExpr(E, AggValueSlot::forAddr(Temp, LV.isVolatileQualified(), false));
+ EmitAggExpr(E, AggValueSlot::forLValue(LV, false));
return LV;
}
@@ -954,7 +1098,10 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr,
llvm::Type::getInt8PtrTy(getLLVMContext(), SPT->getAddressSpace());
SrcPtr = Builder.CreateBitCast(SrcPtr, SBP, "tmp");
- if (const RecordType *RecordTy = Ty->getAs<RecordType>()) {
+ // Don't do any of the memmove_collectable tests if GC isn't set.
+ if (CGM.getLangOptions().getGCMode() == LangOptions::NonGC) {
+ // fall through
+ } else if (const RecordType *RecordTy = Ty->getAs<RecordType>()) {
RecordDecl *Record = RecordTy->getDecl();
if (Record->hasObjectMember()) {
CharUnits size = TypeInfo.first;
@@ -964,7 +1111,7 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr,
SizeVal);
return;
}
- } else if (getContext().getAsArrayType(Ty)) {
+ } else if (Ty->isArrayType()) {
QualType BaseType = getContext().getBaseElementType(Ty);
if (const RecordType *RecordTy = BaseType->getAs<RecordType>()) {
if (RecordTy->getDecl()->hasObjectMember()) {
diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp
index 81fee677f61a..4396f567f2f9 100644
--- a/lib/CodeGen/CGExprCXX.cpp
+++ b/lib/CodeGen/CGExprCXX.cpp
@@ -379,19 +379,11 @@ CodeGenFunction::EmitCXXConstructExpr(const CXXConstructExpr *E,
}
}
- const ConstantArrayType *Array
- = getContext().getAsConstantArrayType(E->getType());
- if (Array) {
- QualType BaseElementTy = getContext().getBaseElementType(Array);
- const llvm::Type *BasePtr = ConvertType(BaseElementTy);
- BasePtr = llvm::PointerType::getUnqual(BasePtr);
- llvm::Value *BaseAddrPtr =
- Builder.CreateBitCast(Dest.getAddr(), BasePtr);
-
- EmitCXXAggrConstructorCall(CD, Array, BaseAddrPtr,
+ if (const ConstantArrayType *arrayType
+ = getContext().getAsConstantArrayType(E->getType())) {
+ EmitCXXAggrConstructorCall(CD, arrayType, Dest.getAddr(),
E->arg_begin(), E->arg_end());
- }
- else {
+ } else {
CXXCtorType Type = Ctor_Complete;
bool ForVirtualBase = false;
@@ -619,10 +611,8 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
// can be ignored because the result shouldn't be used if
// allocation fails.
if (typeSizeMultiplier != 1) {
- const llvm::Type *intrinsicTypes[] = { CGF.SizeTy };
llvm::Value *umul_with_overflow
- = CGF.CGM.getIntrinsic(llvm::Intrinsic::umul_with_overflow,
- intrinsicTypes, 1);
+ = CGF.CGM.getIntrinsic(llvm::Intrinsic::umul_with_overflow, CGF.SizeTy);
llvm::Value *tsmV =
llvm::ConstantInt::get(CGF.SizeTy, typeSizeMultiplier);
@@ -661,10 +651,8 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
if (cookieSize != 0) {
sizeWithoutCookie = size;
- const llvm::Type *intrinsicTypes[] = { CGF.SizeTy };
llvm::Value *uadd_with_overflow
- = CGF.CGM.getIntrinsic(llvm::Intrinsic::uadd_with_overflow,
- intrinsicTypes, 1);
+ = CGF.CGM.getIntrinsic(llvm::Intrinsic::uadd_with_overflow, CGF.SizeTy);
llvm::Value *cookieSizeV = llvm::ConstantInt::get(CGF.SizeTy, cookieSize);
llvm::Value *result =
@@ -707,16 +695,15 @@ static void StoreAnyExprIntoOneUnit(CodeGenFunction &CGF, const CXXNewExpr *E,
unsigned Alignment =
CGF.getContext().getTypeAlignInChars(AllocType).getQuantity();
- if (!CGF.hasAggregateLLVMType(AllocType))
- CGF.EmitStoreOfScalar(CGF.EmitScalarExpr(Init), NewPtr,
- AllocType.isVolatileQualified(), Alignment,
- AllocType);
+ if (!CGF.hasAggregateLLVMType(AllocType))
+ CGF.EmitScalarInit(Init, 0, CGF.MakeAddrLValue(NewPtr, AllocType, Alignment),
+ false);
else if (AllocType->isAnyComplexType())
CGF.EmitComplexExprIntoAddr(Init, NewPtr,
AllocType.isVolatileQualified());
else {
AggValueSlot Slot
- = AggValueSlot::forAddr(NewPtr, AllocType.isVolatileQualified(), true);
+ = AggValueSlot::forAddr(NewPtr, AllocType.getQualifiers(), true);
CGF.EmitAggExpr(Init, Slot);
}
}
@@ -806,7 +793,7 @@ static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E,
RequiresZeroInitialization = true;
}
-
+
CGF.EmitCXXAggrConstructorCall(Ctor, NumElements, NewPtr,
E->constructor_arg_begin(),
E->constructor_arg_end(),
@@ -875,7 +862,7 @@ namespace {
getPlacementArgs()[I] = Arg;
}
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
const FunctionProtoType *FPT
= OperatorDelete->getType()->getAs<FunctionProtoType>();
assert(FPT->getNumArgs() == NumPlacementArgs + 1 ||
@@ -932,7 +919,7 @@ namespace {
getPlacementArgs()[I] = Arg;
}
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
const FunctionProtoType *FPT
= OperatorDelete->getType()->getAs<FunctionProtoType>();
assert(FPT->getNumArgs() == NumPlacementArgs + 1 ||
@@ -1075,7 +1062,7 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
// CXXNewExpr::shouldNullCheckAllocation()) and we have an
// interesting initializer.
bool nullCheck = allocatorType->isNothrow(getContext()) &&
- !(allocType->isPODType() && !E->hasInitializer());
+ !(allocType.isPODType(getContext()) && !E->hasInitializer());
llvm::BasicBlock *nullCheckBB = 0;
llvm::BasicBlock *contBB = 0;
@@ -1202,7 +1189,7 @@ namespace {
QualType ElementType)
: Ptr(Ptr), OperatorDelete(OperatorDelete), ElementType(ElementType) {}
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
CGF.EmitDeleteCall(OperatorDelete, Ptr, ElementType);
}
};
@@ -1212,7 +1199,8 @@ namespace {
static void EmitObjectDelete(CodeGenFunction &CGF,
const FunctionDecl *OperatorDelete,
llvm::Value *Ptr,
- QualType ElementType) {
+ QualType ElementType,
+ bool UseGlobalDelete) {
// Find the destructor for the type, if applicable. If the
// destructor is virtual, we'll just emit the vcall and return.
const CXXDestructorDecl *Dtor = 0;
@@ -1222,17 +1210,30 @@ static void EmitObjectDelete(CodeGenFunction &CGF,
Dtor = RD->getDestructor();
if (Dtor->isVirtual()) {
+ if (UseGlobalDelete) {
+ // If we're supposed to call the global delete, make sure we do so
+ // even if the destructor throws.
+ CGF.EHStack.pushCleanup<CallObjectDelete>(NormalAndEHCleanup,
+ Ptr, OperatorDelete,
+ ElementType);
+ }
+
const llvm::Type *Ty =
CGF.getTypes().GetFunctionType(CGF.getTypes().getFunctionInfo(Dtor,
Dtor_Complete),
/*isVariadic=*/false);
llvm::Value *Callee
- = CGF.BuildVirtualCall(Dtor, Dtor_Deleting, Ptr, Ty);
+ = CGF.BuildVirtualCall(Dtor,
+ UseGlobalDelete? Dtor_Complete : Dtor_Deleting,
+ Ptr, Ty);
CGF.EmitCXXMemberCall(Dtor, Callee, ReturnValueSlot(), Ptr, /*VTT=*/0,
0, 0);
- // The dtor took care of deleting the object.
+ if (UseGlobalDelete) {
+ CGF.PopCleanupBlock();
+ }
+
return;
}
}
@@ -1247,7 +1248,29 @@ static void EmitObjectDelete(CodeGenFunction &CGF,
if (Dtor)
CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete,
/*ForVirtualBase=*/false, Ptr);
+ else if (CGF.getLangOptions().ObjCAutoRefCount &&
+ ElementType->isObjCLifetimeType()) {
+ switch (ElementType.getObjCLifetime()) {
+ case Qualifiers::OCL_None:
+ case Qualifiers::OCL_ExplicitNone:
+ case Qualifiers::OCL_Autoreleasing:
+ break;
+ case Qualifiers::OCL_Strong: {
+ // Load the pointer value.
+ llvm::Value *PtrValue = CGF.Builder.CreateLoad(Ptr,
+ ElementType.isVolatileQualified());
+
+ CGF.EmitARCRelease(PtrValue, /*precise*/ true);
+ break;
+ }
+
+ case Qualifiers::OCL_Weak:
+ CGF.EmitARCDestroyWeak(Ptr);
+ break;
+ }
+ }
+
CGF.PopCleanupBlock();
}
@@ -1268,7 +1291,7 @@ namespace {
: Ptr(Ptr), OperatorDelete(OperatorDelete), NumElements(NumElements),
ElementType(ElementType), CookieSize(CookieSize) {}
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
const FunctionProtoType *DeleteFTy =
OperatorDelete->getType()->getAs<FunctionProtoType>();
assert(DeleteFTy->getNumArgs() == 1 || DeleteFTy->getNumArgs() == 2);
@@ -1316,31 +1339,40 @@ namespace {
/// Emit the code for deleting an array of objects.
static void EmitArrayDelete(CodeGenFunction &CGF,
const CXXDeleteExpr *E,
- llvm::Value *Ptr,
- QualType ElementType) {
- llvm::Value *NumElements = 0;
- llvm::Value *AllocatedPtr = 0;
- CharUnits CookieSize;
- CGF.CGM.getCXXABI().ReadArrayCookie(CGF, Ptr, E, ElementType,
- NumElements, AllocatedPtr, CookieSize);
+ llvm::Value *deletedPtr,
+ QualType elementType) {
+ llvm::Value *numElements = 0;
+ llvm::Value *allocatedPtr = 0;
+ CharUnits cookieSize;
+ CGF.CGM.getCXXABI().ReadArrayCookie(CGF, deletedPtr, E, elementType,
+ numElements, allocatedPtr, cookieSize);
- assert(AllocatedPtr && "ReadArrayCookie didn't set AllocatedPtr");
+ assert(allocatedPtr && "ReadArrayCookie didn't set allocated pointer");
// Make sure that we call delete even if one of the dtors throws.
- const FunctionDecl *OperatorDelete = E->getOperatorDelete();
+ const FunctionDecl *operatorDelete = E->getOperatorDelete();
CGF.EHStack.pushCleanup<CallArrayDelete>(NormalAndEHCleanup,
- AllocatedPtr, OperatorDelete,
- NumElements, ElementType,
- CookieSize);
-
- if (const CXXRecordDecl *RD = ElementType->getAsCXXRecordDecl()) {
- if (!RD->hasTrivialDestructor()) {
- assert(NumElements && "ReadArrayCookie didn't find element count"
- " for a class with destructor");
- CGF.EmitCXXAggrDestructorCall(RD->getDestructor(), NumElements, Ptr);
- }
+ allocatedPtr, operatorDelete,
+ numElements, elementType,
+ cookieSize);
+
+ // Destroy the elements.
+ if (QualType::DestructionKind dtorKind = elementType.isDestructedType()) {
+ assert(numElements && "no element count for a type with a destructor!");
+
+ llvm::Value *arrayEnd =
+ CGF.Builder.CreateInBoundsGEP(deletedPtr, numElements, "delete.end");
+
+ // Note that it is legal to allocate a zero-length array, and we
+ // can never fold the check away because the length should always
+ // come from a cookie.
+ CGF.emitArrayDestroy(deletedPtr, arrayEnd, elementType,
+ CGF.getDestroyer(dtorKind),
+ /*checkZeroLength*/ true,
+ CGF.needsEHCleanup(dtorKind));
}
+ // Pop the cleanup block.
CGF.PopCleanupBlock();
}
@@ -1397,7 +1429,8 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) {
if (E->isArrayForm()) {
EmitArrayDelete(*this, E, Ptr, DeleteTy);
} else {
- EmitObjectDelete(*this, E->getOperatorDelete(), Ptr, DeleteTy);
+ EmitObjectDelete(*this, E->getOperatorDelete(), Ptr, DeleteTy,
+ E->isGlobalDelete());
}
EmitBlock(DeleteEnd);
@@ -1415,7 +1448,7 @@ static llvm::Constant *getBadTypeidFn(CodeGenFunction &CGF) {
static void EmitBadTypeidCall(CodeGenFunction &CGF) {
llvm::Value *Fn = getBadTypeidFn(CGF);
- CGF.EmitCallOrInvoke(Fn, 0, 0).setDoesNotReturn();
+ CGF.EmitCallOrInvoke(Fn).setDoesNotReturn();
CGF.Builder.CreateUnreachable();
}
@@ -1489,11 +1522,11 @@ static llvm::Constant *getDynamicCastFn(CodeGenFunction &CGF) {
// const abi::__class_type_info *dst,
// std::ptrdiff_t src2dst_offset);
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
- const llvm::Type *PtrDiffTy =
+ llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
+ llvm::Type *PtrDiffTy =
CGF.ConvertType(CGF.getContext().getPointerDiffType());
- const llvm::Type *Args[4] = { Int8PtrTy, Int8PtrTy, Int8PtrTy, PtrDiffTy };
+ llvm::Type *Args[4] = { Int8PtrTy, Int8PtrTy, Int8PtrTy, PtrDiffTy };
const llvm::FunctionType *FTy =
llvm::FunctionType::get(Int8PtrTy, Args, false);
@@ -1513,7 +1546,7 @@ static llvm::Constant *getBadCastFn(CodeGenFunction &CGF) {
static void EmitBadCastCall(CodeGenFunction &CGF) {
llvm::Value *Fn = getBadCastFn(CGF);
- CGF.EmitCallOrInvoke(Fn, 0, 0).setDoesNotReturn();
+ CGF.EmitCallOrInvoke(Fn).setDoesNotReturn();
CGF.Builder.CreateUnreachable();
}
diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp
index bd1958602484..35cff1d72714 100644
--- a/lib/CodeGen/CGExprComplex.cpp
+++ b/lib/CodeGen/CGExprComplex.cpp
@@ -112,6 +112,10 @@ public:
return Visit(GE->getResultExpr());
}
ComplexPairTy VisitImaginaryLiteral(const ImaginaryLiteral *IL);
+ ComplexPairTy
+ VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *PE) {
+ return Visit(PE->getReplacement());
+ }
// l-values.
ComplexPairTy VisitDeclRefExpr(const Expr *E) { return EmitLoadOfLValue(E); }
@@ -352,6 +356,8 @@ ComplexPairTy ComplexExprEmitter::EmitComplexToComplexCast(ComplexPairTy Val,
ComplexPairTy ComplexExprEmitter::EmitCast(CastExpr::CastKind CK, Expr *Op,
QualType DestTy) {
switch (CK) {
+ case CK_Dependent: llvm_unreachable("dependent cast kind in IR gen!");
+
case CK_GetObjCProperty: {
LValue LV = CGF.EmitLValue(Op);
assert(LV.isPropertyRef() && "Unknown LValue type!");
@@ -360,39 +366,74 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastExpr::CastKind CK, Expr *Op,
case CK_NoOp:
case CK_LValueToRValue:
+ case CK_UserDefinedConversion:
return Visit(Op);
- // TODO: do all of these
- default:
- break;
- }
-
- // Two cases here: cast from (complex to complex) and (scalar to complex).
- if (Op->getType()->isAnyComplexType())
- return EmitComplexToComplexCast(Visit(Op), Op->getType(), DestTy);
-
- // FIXME: We should be looking at all of the cast kinds here, not
- // cherry-picking the ones we have test cases for.
- if (CK == CK_LValueBitCast) {
+ case CK_LValueBitCast: {
llvm::Value *V = CGF.EmitLValue(Op).getAddress();
V = Builder.CreateBitCast(V,
- CGF.ConvertType(CGF.getContext().getPointerType(DestTy)));
+ CGF.ConvertType(CGF.getContext().getPointerType(DestTy)));
// FIXME: Are the qualifiers correct here?
return EmitLoadOfComplex(V, DestTy.isVolatileQualified());
}
-
- // C99 6.3.1.7: When a value of real type is converted to a complex type, the
- // real part of the complex result value is determined by the rules of
- // conversion to the corresponding real type and the imaginary part of the
- // complex result value is a positive zero or an unsigned zero.
- llvm::Value *Elt = CGF.EmitScalarExpr(Op);
-
- // Convert the input element to the element type of the complex.
- DestTy = DestTy->getAs<ComplexType>()->getElementType();
- Elt = CGF.EmitScalarConversion(Elt, Op->getType(), DestTy);
-
- // Return (realval, 0).
- return ComplexPairTy(Elt, llvm::Constant::getNullValue(Elt->getType()));
+
+ case CK_BitCast:
+ case CK_BaseToDerived:
+ case CK_DerivedToBase:
+ case CK_UncheckedDerivedToBase:
+ case CK_Dynamic:
+ case CK_ToUnion:
+ case CK_ArrayToPointerDecay:
+ case CK_FunctionToPointerDecay:
+ case CK_NullToPointer:
+ case CK_NullToMemberPointer:
+ case CK_BaseToDerivedMemberPointer:
+ case CK_DerivedToBaseMemberPointer:
+ case CK_MemberPointerToBoolean:
+ case CK_ConstructorConversion:
+ case CK_IntegralToPointer:
+ case CK_PointerToIntegral:
+ case CK_PointerToBoolean:
+ case CK_ToVoid:
+ case CK_VectorSplat:
+ case CK_IntegralCast:
+ case CK_IntegralToBoolean:
+ case CK_IntegralToFloating:
+ case CK_FloatingToIntegral:
+ case CK_FloatingToBoolean:
+ case CK_FloatingCast:
+ case CK_AnyPointerToObjCPointerCast:
+ case CK_AnyPointerToBlockPointerCast:
+ case CK_ObjCObjectLValueCast:
+ case CK_FloatingComplexToReal:
+ case CK_FloatingComplexToBoolean:
+ case CK_IntegralComplexToReal:
+ case CK_IntegralComplexToBoolean:
+ case CK_ObjCProduceObject:
+ case CK_ObjCConsumeObject:
+ case CK_ObjCReclaimReturnedObject:
+ llvm_unreachable("invalid cast kind for complex value");
+
+ case CK_FloatingRealToComplex:
+ case CK_IntegralRealToComplex: {
+ llvm::Value *Elt = CGF.EmitScalarExpr(Op);
+
+ // Convert the input element to the element type of the complex.
+ DestTy = DestTy->getAs<ComplexType>()->getElementType();
+ Elt = CGF.EmitScalarConversion(Elt, Op->getType(), DestTy);
+
+ // Return (realval, 0).
+ return ComplexPairTy(Elt, llvm::Constant::getNullValue(Elt->getType()));
+ }
+
+ case CK_FloatingComplexCast:
+ case CK_FloatingComplexToIntegralComplex:
+ case CK_IntegralComplexCast:
+ case CK_IntegralComplexToFloatingComplex:
+ return EmitComplexToComplexCast(Visit(Op), Op->getType(), DestTy);
+ }
+
+ llvm_unreachable("unknown cast resulting in complex value");
}
ComplexPairTy ComplexExprEmitter::VisitUnaryMinus(const UnaryOperator *E) {
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index da37bd5b0a1f..45e44dda0f58 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -433,9 +433,19 @@ llvm::Constant *ConstStructBuilder::
if (!Builder.Build(ILE))
return 0;
+ // Pick the type to use. If the type is layout identical to the ConvertType
+ // type then use it, otherwise use whatever the builder produced for us.
+ const llvm::StructType *STy =
+ llvm::ConstantStruct::getTypeForElements(CGM.getLLVMContext(),
+ Builder.Elements,Builder.Packed);
+ const llvm::Type *ILETy = CGM.getTypes().ConvertType(ILE->getType());
+ if (const llvm::StructType *ILESTy = dyn_cast<llvm::StructType>(ILETy)) {
+ if (ILESTy->isLayoutIdentical(STy))
+ STy = ILESTy;
+ }
+
llvm::Constant *Result =
- llvm::ConstantStruct::get(CGM.getLLVMContext(),
- Builder.Elements, Builder.Packed);
+ llvm::ConstantStruct::get(STy, Builder.Elements);
assert(Builder.NextFieldOffsetInChars.RoundUpToAlignment(
Builder.getAlignment(Result)) ==
@@ -471,6 +481,11 @@ public:
return Visit(PE->getSubExpr());
}
+ llvm::Constant *
+ VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *PE) {
+ return Visit(PE->getReplacement());
+ }
+
llvm::Constant *VisitGenericSelectionExpr(GenericSelectionExpr *GE) {
return Visit(GE->getResultExpr());
}
@@ -523,7 +538,7 @@ public:
// Build a struct with the union sub-element as the first member,
// and padded to the appropriate size
std::vector<llvm::Constant*> Elts;
- std::vector<const llvm::Type*> Types;
+ std::vector<llvm::Type*> Types;
Elts.push_back(C);
Types.push_back(C->getType());
unsigned CurSize = CGM.getTargetData().getTypeAllocSize(C->getType());
@@ -531,7 +546,7 @@ public:
assert(CurSize <= TotalSize && "Union size mismatch!");
if (unsigned NumPadBytes = TotalSize - CurSize) {
- const llvm::Type *Ty = llvm::Type::getInt8Ty(VMContext);
+ llvm::Type *Ty = llvm::Type::getInt8Ty(VMContext);
if (NumPadBytes > 1)
Ty = llvm::ArrayType::get(Ty, NumPadBytes);
@@ -570,6 +585,9 @@ public:
case CK_GetObjCProperty:
case CK_ToVoid:
case CK_Dynamic:
+ case CK_ObjCProduceObject:
+ case CK_ObjCConsumeObject:
+ case CK_ObjCReclaimReturnedObject:
return 0;
// These might need to be supported for constexpr.
@@ -650,6 +668,10 @@ public:
return Visit(DAE->getExpr());
}
+ llvm::Constant *VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) {
+ return Visit(E->GetTemporaryExpr());
+ }
+
llvm::Constant *EmitArrayInitialization(InitListExpr *ILE) {
unsigned NumInitElements = ILE->getNumInits();
if (NumInitElements == 1 && ILE->getType() == ILE->getInit(0)->getType() &&
@@ -694,7 +716,7 @@ public:
if (RewriteType) {
// FIXME: Try to avoid packing the array
- std::vector<const llvm::Type*> Types;
+ std::vector<llvm::Type*> Types;
for (unsigned i = 0; i < Elts.size(); ++i)
Types.push_back(Elts[i]->getType());
const llvm::StructType *SType = llvm::StructType::get(AType->getContext(),
@@ -986,7 +1008,10 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E,
Result.Val.getComplexIntImag());
// FIXME: the target may want to specify that this is packed.
- return llvm::ConstantStruct::get(VMContext, Complex, 2, false);
+ llvm::StructType *STy = llvm::StructType::get(Complex[0]->getType(),
+ Complex[1]->getType(),
+ NULL);
+ return llvm::ConstantStruct::get(STy, Complex);
}
case APValue::Float:
return llvm::ConstantFP::get(VMContext, Result.Val.getFloat());
@@ -999,7 +1024,10 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E,
Result.Val.getComplexFloatImag());
// FIXME: the target may want to specify that this is packed.
- return llvm::ConstantStruct::get(VMContext, Complex, 2, false);
+ llvm::StructType *STy = llvm::StructType::get(Complex[0]->getType(),
+ Complex[1]->getType(),
+ NULL);
+ return llvm::ConstantStruct::get(STy, Complex);
}
case APValue::Vector: {
llvm::SmallVector<llvm::Constant *, 4> Inits;
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index dff7bf45e0c3..a73e667e780e 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -82,15 +82,15 @@ public:
LValue EmitLValue(const Expr *E) { return CGF.EmitLValue(E); }
LValue EmitCheckedLValue(const Expr *E) { return CGF.EmitCheckedLValue(E); }
- Value *EmitLoadOfLValue(LValue LV, QualType T) {
- return CGF.EmitLoadOfLValue(LV, T).getScalarVal();
+ Value *EmitLoadOfLValue(LValue LV) {
+ return CGF.EmitLoadOfLValue(LV).getScalarVal();
}
/// EmitLoadOfLValue - Given an expression with complex type that represents a
/// value l-value, this method emits the address of the l-value, then loads
/// and returns the result.
Value *EmitLoadOfLValue(const Expr *E) {
- return EmitLoadOfLValue(EmitCheckedLValue(E), E->getType());
+ return EmitLoadOfLValue(EmitCheckedLValue(E));
}
/// EmitConversionToBool - Convert the specified expression value to a
@@ -161,6 +161,9 @@ public:
Value *VisitParenExpr(ParenExpr *PE) {
return Visit(PE->getSubExpr());
}
+ Value *VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *E) {
+ return Visit(E->getReplacement());
+ }
Value *VisitGenericSelectionExpr(GenericSelectionExpr *GE) {
return Visit(GE->getResultExpr());
}
@@ -197,7 +200,7 @@ public:
Value *VisitOpaqueValueExpr(OpaqueValueExpr *E) {
if (E->isGLValue())
- return EmitLoadOfLValue(CGF.getOpaqueLValueMapping(E), E->getType());
+ return EmitLoadOfLValue(CGF.getOpaqueLValueMapping(E));
// Otherwise, assume the mapping is the scalar directly.
return CGF.getOpaqueRValueMapping(E).getScalarVal();
@@ -252,7 +255,7 @@ public:
Value *VisitObjCIsaExpr(ObjCIsaExpr *E) {
LValue LV = CGF.EmitObjCIsaExpr(E);
- Value *V = CGF.EmitLoadOfLValue(LV, E->getType()).getScalarVal();
+ Value *V = CGF.EmitLoadOfLValue(LV).getScalarVal();
return V;
}
@@ -269,14 +272,12 @@ public:
Value *VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) {
return CGF.CGM.EmitNullConstant(E->getType());
}
- Value *VisitCastExpr(CastExpr *E) {
- // Make sure to evaluate VLA bounds now so that we have them for later.
+ Value *VisitExplicitCastExpr(ExplicitCastExpr *E) {
if (E->getType()->isVariablyModifiedType())
- CGF.EmitVLASize(E->getType());
-
- return EmitCastExpr(E);
+ CGF.EmitVariablyModifiedType(E->getType());
+ return VisitCastExpr(E);
}
- Value *EmitCastExpr(CastExpr *E);
+ Value *VisitCastExpr(CastExpr *E);
Value *VisitCallExpr(const CallExpr *E) {
if (E->getCallReturnType()->isReferenceType())
@@ -1001,7 +1002,7 @@ static bool ShouldNullCheckClassCastValue(const CastExpr *CE) {
// VisitCastExpr - Emit code for an explicit or implicit cast. Implicit casts
// have to handle a more broad range of conversions than explicit casts, as they
// handle things like function to ptr-to-function decay etc.
-Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) {
+Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
Expr *E = CE->getSubExpr();
QualType DestTy = CE->getType();
CastKind Kind = CE->getCastKind();
@@ -1020,7 +1021,7 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) {
Value *V = EmitLValue(E).getAddress();
V = Builder.CreateBitCast(V,
ConvertType(CGF.getContext().getPointerType(DestTy)));
- return EmitLoadOfLValue(CGF.MakeAddrLValue(V, DestTy), DestTy);
+ return EmitLoadOfLValue(CGF.MakeAddrLValue(V, DestTy));
}
case CK_AnyPointerToObjCPointerCast:
@@ -1106,7 +1107,17 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) {
// function pointers on Itanium and ARM).
return CGF.CGM.getCXXABI().EmitMemberPointerConversion(CGF, CE, Src);
}
-
+
+ case CK_ObjCProduceObject:
+ return CGF.EmitARCRetainScalarExpr(E);
+ case CK_ObjCConsumeObject:
+ return CGF.EmitObjCConsumeObject(E->getType(), Visit(E));
+ case CK_ObjCReclaimReturnedObject: {
+ llvm::Value *value = Visit(E);
+ value = CGF.EmitARCRetainAutoreleasedReturnValue(value);
+ return CGF.EmitObjCConsumeObject(E->getType(), value);
+ }
+
case CK_FloatingRealToComplex:
case CK_FloatingComplexCast:
case CK_IntegralRealToComplex:
@@ -1122,7 +1133,7 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) {
assert(CGF.getContext().hasSameUnqualifiedType(E->getType(), DestTy));
assert(E->isGLValue() && E->getObjectKind() == OK_ObjCProperty &&
"CK_GetObjCProperty for non-lvalue or non-ObjCProperty");
- RValue RV = CGF.EmitLoadOfLValue(CGF.EmitLValue(E), E->getType());
+ RValue RV = CGF.EmitLoadOfLValue(CGF.EmitLValue(E));
return RV.getScalarVal();
}
@@ -1143,15 +1154,10 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) {
return Builder.CreateIntToPtr(IntResult, ConvertType(DestTy));
}
- case CK_PointerToIntegral: {
- Value *Src = Visit(const_cast<Expr*>(E));
-
- // Handle conversion to bool correctly.
- if (DestTy->isBooleanType())
- return EmitScalarConversion(Src, E->getType(), DestTy);
+ case CK_PointerToIntegral:
+ assert(!DestTy->isBooleanType() && "bool should use PointerToBool");
+ return Builder.CreatePtrToInt(Visit(E), ConvertType(DestTy));
- return Builder.CreatePtrToInt(Src, ConvertType(DestTy));
- }
case CK_ToVoid: {
CGF.EmitIgnoredExpr(E);
return 0;
@@ -1221,7 +1227,7 @@ Value *ScalarExprEmitter::VisitStmtExpr(const StmtExpr *E) {
Value *ScalarExprEmitter::VisitBlockDeclRefExpr(const BlockDeclRefExpr *E) {
LValue LV = CGF.EmitBlockDeclRefLValue(E);
- return CGF.EmitLoadOfLValue(LV, E->getType()).getScalarVal();
+ return CGF.EmitLoadOfLValue(LV).getScalarVal();
}
//===----------------------------------------------------------------------===//
@@ -1258,7 +1264,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
bool isInc, bool isPre) {
QualType type = E->getSubExpr()->getType();
- llvm::Value *value = EmitLoadOfLValue(LV, type);
+ llvm::Value *value = EmitLoadOfLValue(LV);
llvm::Value *input = value;
int amount = (isInc ? 1 : -1);
@@ -1282,7 +1288,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
// overflow because of promotion rules; we're just eliding a few steps here.
if (type->isSignedIntegerOrEnumerationType() &&
value->getType()->getPrimitiveSizeInBits() >=
- CGF.CGM.IntTy->getBitWidth())
+ CGF.IntTy->getBitWidth())
value = EmitAddConsiderOverflowBehavior(E, value, amt, isInc);
else
value = Builder.CreateAdd(value, amt, isInc ? "inc" : "dec");
@@ -1292,16 +1298,14 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
QualType type = ptr->getPointeeType();
// VLA types don't have constant size.
- if (type->isVariableArrayType()) {
- llvm::Value *vlaSize =
- CGF.GetVLASize(CGF.getContext().getAsVariableArrayType(type));
- value = CGF.EmitCastToVoidPtr(value);
- if (!isInc) vlaSize = Builder.CreateNSWNeg(vlaSize, "vla.negsize");
+ if (const VariableArrayType *vla
+ = CGF.getContext().getAsVariableArrayType(type)) {
+ llvm::Value *numElts = CGF.getVLASize(vla).first;
+ if (!isInc) numElts = Builder.CreateNSWNeg(numElts, "vla.negsize");
if (CGF.getContext().getLangOptions().isSignedOverflowDefined())
- value = Builder.CreateGEP(value, vlaSize, "vla.inc");
+ value = Builder.CreateGEP(value, numElts, "vla.inc");
else
- value = Builder.CreateInBoundsGEP(value, vlaSize, "vla.inc");
- value = Builder.CreateBitCast(value, input->getType());
+ value = Builder.CreateInBoundsGEP(value, numElts, "vla.inc");
// Arithmetic on function pointers (!) is just +-1.
} else if (type->isFunctionType()) {
@@ -1374,9 +1378,9 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
// Store the updated result through the lvalue.
if (LV.isBitField())
- CGF.EmitStoreThroughBitfieldLValue(RValue::get(value), LV, type, &value);
+ CGF.EmitStoreThroughBitfieldLValue(RValue::get(value), LV, &value);
else
- CGF.EmitStoreThroughLValue(RValue::get(value), LV, type);
+ CGF.EmitStoreThroughLValue(RValue::get(value), LV);
// If this is a postinc, return the value read from memory, otherwise use the
// updated value.
@@ -1521,14 +1525,25 @@ ScalarExprEmitter::VisitUnaryExprOrTypeTraitExpr(
CGF.getContext().getAsVariableArrayType(TypeToSize)) {
if (E->isArgumentType()) {
// sizeof(type) - make sure to emit the VLA size.
- CGF.EmitVLASize(TypeToSize);
+ CGF.EmitVariablyModifiedType(TypeToSize);
} else {
// C99 6.5.3.4p2: If the argument is an expression of type
// VLA, it is evaluated.
CGF.EmitIgnoredExpr(E->getArgumentExpr());
}
- return CGF.GetVLASize(VAT);
+ QualType eltType;
+ llvm::Value *numElts;
+ llvm::tie(numElts, eltType) = CGF.getVLASize(VAT);
+
+ llvm::Value *size = numElts;
+
+ // Scale the number of non-VLA elements by the non-VLA element size.
+ CharUnits eltSize = CGF.getContext().getTypeSizeInChars(eltType);
+ if (!eltSize.isOne())
+ size = CGF.Builder.CreateNUWMul(CGF.CGM.getSize(eltSize), numElts);
+
+ return size;
}
}
@@ -1546,8 +1561,7 @@ Value *ScalarExprEmitter::VisitUnaryReal(const UnaryOperator *E) {
// Note that we have to ask E because Op might be an l-value that
// this won't work for, e.g. an Obj-C property.
if (E->isGLValue())
- return CGF.EmitLoadOfLValue(CGF.EmitLValue(E), E->getType())
- .getScalarVal();
+ return CGF.EmitLoadOfLValue(CGF.EmitLValue(E)).getScalarVal();
// Otherwise, calculate and project.
return CGF.EmitComplexExpr(Op, false, true).first;
@@ -1563,8 +1577,7 @@ Value *ScalarExprEmitter::VisitUnaryImag(const UnaryOperator *E) {
// Note that we have to ask E because Op might be an l-value that
// this won't work for, e.g. an Obj-C property.
if (Op->isGLValue())
- return CGF.EmitLoadOfLValue(CGF.EmitLValue(E), E->getType())
- .getScalarVal();
+ return CGF.EmitLoadOfLValue(CGF.EmitLValue(E)).getScalarVal();
// Otherwise, calculate and project.
return CGF.EmitComplexExpr(Op, true, false).second;
@@ -1616,7 +1629,7 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue(
OpInfo.E = E;
// Load/convert the LHS.
LValue LHSLV = EmitCheckedLValue(E->getLHS());
- OpInfo.LHS = EmitLoadOfLValue(LHSLV, LHSTy);
+ OpInfo.LHS = EmitLoadOfLValue(LHSLV);
OpInfo.LHS = EmitScalarConversion(OpInfo.LHS, LHSTy,
E->getComputationLHSType());
@@ -1631,10 +1644,9 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue(
// 'An assignment expression has the value of the left operand after the
// assignment...'.
if (LHSLV.isBitField())
- CGF.EmitStoreThroughBitfieldLValue(RValue::get(Result), LHSLV, LHSTy,
- &Result);
+ CGF.EmitStoreThroughBitfieldLValue(RValue::get(Result), LHSLV, &Result);
else
- CGF.EmitStoreThroughLValue(RValue::get(Result), LHSLV, LHSTy);
+ CGF.EmitStoreThroughLValue(RValue::get(Result), LHSLV);
return LHSLV;
}
@@ -1662,15 +1674,17 @@ Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E,
return RHS;
// Otherwise, reload the value.
- return EmitLoadOfLValue(LHS, E->getType());
+ return EmitLoadOfLValue(LHS);
}
void ScalarExprEmitter::EmitUndefinedBehaviorIntegerDivAndRemCheck(
const BinOpInfo &Ops,
llvm::Value *Zero, bool isDiv) {
- llvm::BasicBlock *overflowBB = CGF.createBasicBlock("overflow", CGF.CurFn);
+ llvm::Function::iterator insertPt = Builder.GetInsertBlock();
llvm::BasicBlock *contBB =
- CGF.createBasicBlock(isDiv ? "div.cont" : "rem.cont", CGF.CurFn);
+ CGF.createBasicBlock(isDiv ? "div.cont" : "rem.cont", CGF.CurFn,
+ llvm::next(insertPt));
+ llvm::BasicBlock *overflowBB = CGF.createBasicBlock("overflow", CGF.CurFn);
const llvm::IntegerType *Ty = cast<llvm::IntegerType>(Zero->getType());
@@ -1700,9 +1714,11 @@ Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) {
if (Ops.Ty->isIntegerType())
EmitUndefinedBehaviorIntegerDivAndRemCheck(Ops, Zero, true);
else if (Ops.Ty->isRealFloatingType()) {
+ llvm::Function::iterator insertPt = Builder.GetInsertBlock();
+ llvm::BasicBlock *DivCont = CGF.createBasicBlock("div.cont", CGF.CurFn,
+ llvm::next(insertPt));
llvm::BasicBlock *overflowBB = CGF.createBasicBlock("overflow",
CGF.CurFn);
- llvm::BasicBlock *DivCont = CGF.createBasicBlock("div.cont", CGF.CurFn);
CGF.Builder.CreateCondBr(Builder.CreateFCmpOEQ(Ops.RHS, Zero),
overflowBB, DivCont);
EmitOverflowBB(overflowBB);
@@ -1759,9 +1775,9 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
OpID <<= 1;
OpID |= 1;
- const llvm::Type *opTy = CGF.CGM.getTypes().ConvertType(Ops.Ty);
+ llvm::Type *opTy = CGF.CGM.getTypes().ConvertType(Ops.Ty);
- llvm::Function *intrinsic = CGF.CGM.getIntrinsic(IID, &opTy, 1);
+ llvm::Function *intrinsic = CGF.CGM.getIntrinsic(IID, opTy);
Value *resultAndOverflow = Builder.CreateCall2(intrinsic, Ops.LHS, Ops.RHS);
Value *result = Builder.CreateExtractValue(resultAndOverflow, 0);
@@ -1769,8 +1785,10 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
// Branch in case of overflow.
llvm::BasicBlock *initialBB = Builder.GetInsertBlock();
+ llvm::Function::iterator insertPt = initialBB;
+ llvm::BasicBlock *continueBB = CGF.createBasicBlock("nooverflow", CGF.CurFn,
+ llvm::next(insertPt));
llvm::BasicBlock *overflowBB = CGF.createBasicBlock("overflow", CGF.CurFn);
- llvm::BasicBlock *continueBB = CGF.createBasicBlock("nooverflow", CGF.CurFn);
Builder.CreateCondBr(overflow, overflowBB, continueBB);
@@ -1788,8 +1806,8 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
Builder.SetInsertPoint(overflowBB);
// Get the overflow handler.
- const llvm::Type *Int8Ty = llvm::Type::getInt8Ty(VMContext);
- const llvm::Type *argTypes[] = { CGF.Int64Ty, CGF.Int64Ty, Int8Ty, Int8Ty };
+ llvm::Type *Int8Ty = llvm::Type::getInt8Ty(VMContext);
+ llvm::Type *argTypes[] = { CGF.Int64Ty, CGF.Int64Ty, Int8Ty, Int8Ty };
llvm::FunctionType *handlerTy =
llvm::FunctionType::get(CGF.Int64Ty, argTypes, true);
llvm::Value *handler = CGF.CGM.CreateRuntimeFunction(handlerTy, *handlerName);
@@ -1817,196 +1835,187 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
return phi;
}
-Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) {
- if (!Ops.Ty->isAnyPointerType()) {
- if (Ops.Ty->isSignedIntegerOrEnumerationType()) {
- switch (CGF.getContext().getLangOptions().getSignedOverflowBehavior()) {
- case LangOptions::SOB_Undefined:
- return Builder.CreateNSWAdd(Ops.LHS, Ops.RHS, "add");
- case LangOptions::SOB_Defined:
- return Builder.CreateAdd(Ops.LHS, Ops.RHS, "add");
- case LangOptions::SOB_Trapping:
- return EmitOverflowCheckedBinOp(Ops);
- }
- }
-
- if (Ops.LHS->getType()->isFPOrFPVectorTy())
- return Builder.CreateFAdd(Ops.LHS, Ops.RHS, "add");
-
- return Builder.CreateAdd(Ops.LHS, Ops.RHS, "add");
- }
-
- // Must have binary (not unary) expr here. Unary pointer decrement doesn't
- // use this path.
- const BinaryOperator *BinOp = cast<BinaryOperator>(Ops.E);
-
- if (Ops.Ty->isPointerType() &&
- Ops.Ty->getAs<PointerType>()->isVariableArrayType()) {
- // The amount of the addition needs to account for the VLA size
- CGF.ErrorUnsupported(BinOp, "VLA pointer addition");
- }
+/// Emit pointer + index arithmetic.
+static Value *emitPointerArithmetic(CodeGenFunction &CGF,
+ const BinOpInfo &op,
+ bool isSubtraction) {
+ // Must have binary (not unary) expr here. Unary pointer
+ // increment/decrement doesn't use this path.
+ const BinaryOperator *expr = cast<BinaryOperator>(op.E);
- Value *Ptr, *Idx;
- Expr *IdxExp;
- const PointerType *PT = BinOp->getLHS()->getType()->getAs<PointerType>();
- const ObjCObjectPointerType *OPT =
- BinOp->getLHS()->getType()->getAs<ObjCObjectPointerType>();
- if (PT || OPT) {
- Ptr = Ops.LHS;
- Idx = Ops.RHS;
- IdxExp = BinOp->getRHS();
- } else { // int + pointer
- PT = BinOp->getRHS()->getType()->getAs<PointerType>();
- OPT = BinOp->getRHS()->getType()->getAs<ObjCObjectPointerType>();
- assert((PT || OPT) && "Invalid add expr");
- Ptr = Ops.RHS;
- Idx = Ops.LHS;
- IdxExp = BinOp->getLHS();
- }
-
- unsigned Width = cast<llvm::IntegerType>(Idx->getType())->getBitWidth();
- if (Width < CGF.PointerWidthInBits) {
- // Zero or sign extend the pointer value based on whether the index is
- // signed or not.
- const llvm::Type *IdxType = CGF.IntPtrTy;
- if (IdxExp->getType()->isSignedIntegerOrEnumerationType())
- Idx = Builder.CreateSExt(Idx, IdxType, "idx.ext");
- else
- Idx = Builder.CreateZExt(Idx, IdxType, "idx.ext");
- }
- const QualType ElementType = PT ? PT->getPointeeType() : OPT->getPointeeType();
- // Handle interface types, which are not represented with a concrete type.
- if (const ObjCObjectType *OIT = ElementType->getAs<ObjCObjectType>()) {
- llvm::Value *InterfaceSize =
- llvm::ConstantInt::get(Idx->getType(),
- CGF.getContext().getTypeSizeInChars(OIT).getQuantity());
- Idx = Builder.CreateMul(Idx, InterfaceSize);
- const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(VMContext);
- Value *Casted = Builder.CreateBitCast(Ptr, i8Ty);
- Value *Res = Builder.CreateGEP(Casted, Idx, "add.ptr");
- return Builder.CreateBitCast(Res, Ptr->getType());
+ Value *pointer = op.LHS;
+ Expr *pointerOperand = expr->getLHS();
+ Value *index = op.RHS;
+ Expr *indexOperand = expr->getRHS();
+
+ // In a subtraction, the LHS is always the pointer.
+ if (!isSubtraction && !pointer->getType()->isPointerTy()) {
+ std::swap(pointer, index);
+ std::swap(pointerOperand, indexOperand);
+ }
+
+ unsigned width = cast<llvm::IntegerType>(index->getType())->getBitWidth();
+ if (width != CGF.PointerWidthInBits) {
+ // Zero-extend or sign-extend the pointer value according to
+ // whether the index is signed or not.
+ bool isSigned = indexOperand->getType()->isSignedIntegerOrEnumerationType();
+ index = CGF.Builder.CreateIntCast(index, CGF.PtrDiffTy, isSigned,
+ "idx.ext");
+ }
+
+ // If this is subtraction, negate the index.
+ if (isSubtraction)
+ index = CGF.Builder.CreateNeg(index, "idx.neg");
+
+ const PointerType *pointerType
+ = pointerOperand->getType()->getAs<PointerType>();
+ if (!pointerType) {
+ QualType objectType = pointerOperand->getType()
+ ->castAs<ObjCObjectPointerType>()
+ ->getPointeeType();
+ llvm::Value *objectSize
+ = CGF.CGM.getSize(CGF.getContext().getTypeSizeInChars(objectType));
+
+ index = CGF.Builder.CreateMul(index, objectSize);
+
+ Value *result = CGF.Builder.CreateBitCast(pointer, CGF.VoidPtrTy);
+ result = CGF.Builder.CreateGEP(result, index, "add.ptr");
+ return CGF.Builder.CreateBitCast(result, pointer->getType());
+ }
+
+ QualType elementType = pointerType->getPointeeType();
+ if (const VariableArrayType *vla
+ = CGF.getContext().getAsVariableArrayType(elementType)) {
+ // The element count here is the total number of non-VLA elements.
+ llvm::Value *numElements = CGF.getVLASize(vla).first;
+
+ // Effectively, the multiply by the VLA size is part of the GEP.
+ // GEP indexes are signed, and scaling an index isn't permitted to
+ // signed-overflow, so we use the same semantics for our explicit
+ // multiply. We suppress this if overflow is not undefined behavior.
+ if (CGF.getLangOptions().isSignedOverflowDefined()) {
+ index = CGF.Builder.CreateMul(index, numElements, "vla.index");
+ pointer = CGF.Builder.CreateGEP(pointer, index, "add.ptr");
+ } else {
+ index = CGF.Builder.CreateNSWMul(index, numElements, "vla.index");
+ pointer = CGF.Builder.CreateInBoundsGEP(pointer, index, "add.ptr");
+ }
+ return pointer;
}
// Explicitly handle GNU void* and function pointer arithmetic extensions. The
// GNU void* casts amount to no-ops since our void* type is i8*, but this is
// future proof.
- if (ElementType->isVoidType() || ElementType->isFunctionType()) {
- const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(VMContext);
- Value *Casted = Builder.CreateBitCast(Ptr, i8Ty);
- Value *Res = Builder.CreateGEP(Casted, Idx, "add.ptr");
- return Builder.CreateBitCast(Res, Ptr->getType());
+ if (elementType->isVoidType() || elementType->isFunctionType()) {
+ Value *result = CGF.Builder.CreateBitCast(pointer, CGF.VoidPtrTy);
+ result = CGF.Builder.CreateGEP(result, index, "add.ptr");
+ return CGF.Builder.CreateBitCast(result, pointer->getType());
}
- if (CGF.getContext().getLangOptions().isSignedOverflowDefined())
- return Builder.CreateGEP(Ptr, Idx, "add.ptr");
- return Builder.CreateInBoundsGEP(Ptr, Idx, "add.ptr");
+ if (CGF.getLangOptions().isSignedOverflowDefined())
+ return CGF.Builder.CreateGEP(pointer, index, "add.ptr");
+
+ return CGF.Builder.CreateInBoundsGEP(pointer, index, "add.ptr");
}
-Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) {
- if (!isa<llvm::PointerType>(Ops.LHS->getType())) {
- if (Ops.Ty->isSignedIntegerOrEnumerationType()) {
+Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &op) {
+ if (op.LHS->getType()->isPointerTy() ||
+ op.RHS->getType()->isPointerTy())
+ return emitPointerArithmetic(CGF, op, /*subtraction*/ false);
+
+ if (op.Ty->isSignedIntegerOrEnumerationType()) {
+ switch (CGF.getContext().getLangOptions().getSignedOverflowBehavior()) {
+ case LangOptions::SOB_Undefined:
+ return Builder.CreateNSWAdd(op.LHS, op.RHS, "add");
+ case LangOptions::SOB_Defined:
+ return Builder.CreateAdd(op.LHS, op.RHS, "add");
+ case LangOptions::SOB_Trapping:
+ return EmitOverflowCheckedBinOp(op);
+ }
+ }
+
+ if (op.LHS->getType()->isFPOrFPVectorTy())
+ return Builder.CreateFAdd(op.LHS, op.RHS, "add");
+
+ return Builder.CreateAdd(op.LHS, op.RHS, "add");
+}
+
+Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) {
+ // The LHS is always a pointer if either side is.
+ if (!op.LHS->getType()->isPointerTy()) {
+ if (op.Ty->isSignedIntegerOrEnumerationType()) {
switch (CGF.getContext().getLangOptions().getSignedOverflowBehavior()) {
case LangOptions::SOB_Undefined:
- return Builder.CreateNSWSub(Ops.LHS, Ops.RHS, "sub");
+ return Builder.CreateNSWSub(op.LHS, op.RHS, "sub");
case LangOptions::SOB_Defined:
- return Builder.CreateSub(Ops.LHS, Ops.RHS, "sub");
+ return Builder.CreateSub(op.LHS, op.RHS, "sub");
case LangOptions::SOB_Trapping:
- return EmitOverflowCheckedBinOp(Ops);
+ return EmitOverflowCheckedBinOp(op);
}
}
- if (Ops.LHS->getType()->isFPOrFPVectorTy())
- return Builder.CreateFSub(Ops.LHS, Ops.RHS, "sub");
+ if (op.LHS->getType()->isFPOrFPVectorTy())
+ return Builder.CreateFSub(op.LHS, op.RHS, "sub");
- return Builder.CreateSub(Ops.LHS, Ops.RHS, "sub");
+ return Builder.CreateSub(op.LHS, op.RHS, "sub");
}
- // Must have binary (not unary) expr here. Unary pointer increment doesn't
- // use this path.
- const BinaryOperator *BinOp = cast<BinaryOperator>(Ops.E);
-
- if (BinOp->getLHS()->getType()->isPointerType() &&
- BinOp->getLHS()->getType()->getAs<PointerType>()->isVariableArrayType()) {
- // The amount of the addition needs to account for the VLA size for
- // ptr-int
- // The amount of the division needs to account for the VLA size for
- // ptr-ptr.
- CGF.ErrorUnsupported(BinOp, "VLA pointer subtraction");
- }
-
- const QualType LHSType = BinOp->getLHS()->getType();
- const QualType LHSElementType = LHSType->getPointeeType();
- if (!isa<llvm::PointerType>(Ops.RHS->getType())) {
- // pointer - int
- Value *Idx = Ops.RHS;
- unsigned Width = cast<llvm::IntegerType>(Idx->getType())->getBitWidth();
- if (Width < CGF.PointerWidthInBits) {
- // Zero or sign extend the pointer value based on whether the index is
- // signed or not.
- const llvm::Type *IdxType = CGF.IntPtrTy;
- if (BinOp->getRHS()->getType()->isSignedIntegerOrEnumerationType())
- Idx = Builder.CreateSExt(Idx, IdxType, "idx.ext");
- else
- Idx = Builder.CreateZExt(Idx, IdxType, "idx.ext");
- }
- Idx = Builder.CreateNeg(Idx, "sub.ptr.neg");
-
- // Handle interface types, which are not represented with a concrete type.
- if (const ObjCObjectType *OIT = LHSElementType->getAs<ObjCObjectType>()) {
- llvm::Value *InterfaceSize =
- llvm::ConstantInt::get(Idx->getType(),
- CGF.getContext().
- getTypeSizeInChars(OIT).getQuantity());
- Idx = Builder.CreateMul(Idx, InterfaceSize);
- const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(VMContext);
- Value *LHSCasted = Builder.CreateBitCast(Ops.LHS, i8Ty);
- Value *Res = Builder.CreateGEP(LHSCasted, Idx, "add.ptr");
- return Builder.CreateBitCast(Res, Ops.LHS->getType());
- }
+ // If the RHS is not a pointer, then we have normal pointer
+ // arithmetic.
+ if (!op.RHS->getType()->isPointerTy())
+ return emitPointerArithmetic(CGF, op, /*subtraction*/ true);
- // Explicitly handle GNU void* and function pointer arithmetic
- // extensions. The GNU void* casts amount to no-ops since our void* type is
- // i8*, but this is future proof.
- if (LHSElementType->isVoidType() || LHSElementType->isFunctionType()) {
- const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(VMContext);
- Value *LHSCasted = Builder.CreateBitCast(Ops.LHS, i8Ty);
- Value *Res = Builder.CreateGEP(LHSCasted, Idx, "sub.ptr");
- return Builder.CreateBitCast(Res, Ops.LHS->getType());
- }
+ // Otherwise, this is a pointer subtraction.
- if (CGF.getContext().getLangOptions().isSignedOverflowDefined())
- return Builder.CreateGEP(Ops.LHS, Idx, "sub.ptr");
- return Builder.CreateInBoundsGEP(Ops.LHS, Idx, "sub.ptr");
- }
-
- // pointer - pointer
- Value *LHS = Ops.LHS;
- Value *RHS = Ops.RHS;
+ // Do the raw subtraction part.
+ llvm::Value *LHS
+ = Builder.CreatePtrToInt(op.LHS, CGF.PtrDiffTy, "sub.ptr.lhs.cast");
+ llvm::Value *RHS
+ = Builder.CreatePtrToInt(op.RHS, CGF.PtrDiffTy, "sub.ptr.rhs.cast");
+ Value *diffInChars = Builder.CreateSub(LHS, RHS, "sub.ptr.sub");
- CharUnits ElementSize;
+ // Okay, figure out the element size.
+ const BinaryOperator *expr = cast<BinaryOperator>(op.E);
+ QualType elementType = expr->getLHS()->getType()->getPointeeType();
- // Handle GCC extension for pointer arithmetic on void* and function pointer
- // types.
- if (LHSElementType->isVoidType() || LHSElementType->isFunctionType())
- ElementSize = CharUnits::One();
- else
- ElementSize = CGF.getContext().getTypeSizeInChars(LHSElementType);
+ llvm::Value *divisor = 0;
- const llvm::Type *ResultType = ConvertType(Ops.Ty);
- LHS = Builder.CreatePtrToInt(LHS, ResultType, "sub.ptr.lhs.cast");
- RHS = Builder.CreatePtrToInt(RHS, ResultType, "sub.ptr.rhs.cast");
- Value *BytesBetween = Builder.CreateSub(LHS, RHS, "sub.ptr.sub");
+ // For a variable-length array, this is going to be non-constant.
+ if (const VariableArrayType *vla
+ = CGF.getContext().getAsVariableArrayType(elementType)) {
+ llvm::Value *numElements;
+ llvm::tie(numElements, elementType) = CGF.getVLASize(vla);
- // Optimize out the shift for element size of 1.
- if (ElementSize.isOne())
- return BytesBetween;
+ divisor = numElements;
+ // Scale the number of non-VLA elements by the non-VLA element size.
+ CharUnits eltSize = CGF.getContext().getTypeSizeInChars(elementType);
+ if (!eltSize.isOne())
+ divisor = CGF.Builder.CreateNUWMul(CGF.CGM.getSize(eltSize), divisor);
+
+ // For everything elese, we can just compute it, safe in the
+ // assumption that Sema won't let anything through that we can't
+ // safely compute the size of.
+ } else {
+ CharUnits elementSize;
+ // Handle GCC extension for pointer arithmetic on void* and
+ // function pointer types.
+ if (elementType->isVoidType() || elementType->isFunctionType())
+ elementSize = CharUnits::One();
+ else
+ elementSize = CGF.getContext().getTypeSizeInChars(elementType);
+
+ // Don't even emit the divide for element size of 1.
+ if (elementSize.isOne())
+ return diffInChars;
+
+ divisor = CGF.CGM.getSize(elementSize);
+ }
+
// Otherwise, do a full sdiv. This uses the "exact" form of sdiv, since
// pointer difference in C is only defined in the case where both operands
// are pointing to elements of an array.
- Value *BytesPerElt =
- llvm::ConstantInt::get(ResultType, ElementSize.getQuantity());
- return Builder.CreateExactSDiv(BytesBetween, BytesPerElt, "sub.ptr.div");
+ return Builder.CreateExactSDiv(diffInChars, divisor, "sub.ptr.div");
}
Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) {
@@ -2228,20 +2237,41 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc,
Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) {
bool Ignore = TestAndClearIgnoreResultAssign();
- // __block variables need to have the rhs evaluated first, plus this should
- // improve codegen just a little.
- Value *RHS = Visit(E->getRHS());
- LValue LHS = EmitCheckedLValue(E->getLHS());
-
- // Store the value into the LHS. Bit-fields are handled specially
- // because the result is altered by the store, i.e., [C99 6.5.16p1]
- // 'An assignment expression has the value of the left operand after
- // the assignment...'.
- if (LHS.isBitField())
- CGF.EmitStoreThroughBitfieldLValue(RValue::get(RHS), LHS, E->getType(),
- &RHS);
- else
- CGF.EmitStoreThroughLValue(RValue::get(RHS), LHS, E->getType());
+ Value *RHS;
+ LValue LHS;
+
+ switch (E->getLHS()->getType().getObjCLifetime()) {
+ case Qualifiers::OCL_Strong:
+ llvm::tie(LHS, RHS) = CGF.EmitARCStoreStrong(E, Ignore);
+ break;
+
+ case Qualifiers::OCL_Autoreleasing:
+ llvm::tie(LHS,RHS) = CGF.EmitARCStoreAutoreleasing(E);
+ break;
+
+ case Qualifiers::OCL_Weak:
+ RHS = Visit(E->getRHS());
+ LHS = EmitCheckedLValue(E->getLHS());
+ RHS = CGF.EmitARCStoreWeak(LHS.getAddress(), RHS, Ignore);
+ break;
+
+ // No reason to do any of these differently.
+ case Qualifiers::OCL_None:
+ case Qualifiers::OCL_ExplicitNone:
+ // __block variables need to have the rhs evaluated first, plus
+ // this should improve codegen just a little.
+ RHS = Visit(E->getRHS());
+ LHS = EmitCheckedLValue(E->getLHS());
+
+ // Store the value into the LHS. Bit-fields are handled specially
+ // because the result is altered by the store, i.e., [C99 6.5.16p1]
+ // 'An assignment expression has the value of the left operand after
+ // the assignment...'.
+ if (LHS.isBitField())
+ CGF.EmitStoreThroughBitfieldLValue(RValue::get(RHS), LHS, &RHS);
+ else
+ CGF.EmitStoreThroughLValue(RValue::get(RHS), LHS);
+ }
// If the result is clearly ignored, return now.
if (Ignore)
@@ -2260,7 +2290,7 @@ Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) {
return RHS;
// Otherwise, reload the value.
- return EmitLoadOfLValue(LHS, E->getType());
+ return EmitLoadOfLValue(LHS);
}
Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
@@ -2548,7 +2578,7 @@ Value *ScalarExprEmitter::VisitBlockExpr(const BlockExpr *block) {
Value *ScalarExprEmitter::VisitAsTypeExpr(AsTypeExpr *E) {
Value *Src = CGF.EmitScalarExpr(E->getSrcExpr());
- const llvm::Type * DstTy = ConvertType(E->getDstType());
+ const llvm::Type *DstTy = ConvertType(E->getType());
// Going from vec4->vec3 or vec3->vec4 is a special case and requires
// a shuffle vector instead of a bitcast.
@@ -2656,7 +2686,7 @@ LValue CodeGenFunction::EmitObjCIsaExpr(const ObjCIsaExpr *E) {
llvm::Value *Src = EmitScalarExpr(BaseExpr);
Builder.CreateStore(Src, V);
V = ScalarExprEmitter(*this).EmitLoadOfLValue(
- MakeAddrLValue(V, E->getType()), E->getType());
+ MakeAddrLValue(V, E->getType()));
} else {
if (E->isArrow())
V = ScalarExprEmitter(*this).EmitLoadOfLValue(BaseExpr);
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index fa42cd1f36ab..426cca00140c 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -15,15 +15,29 @@
#include "CGObjCRuntime.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
+#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/StmtObjC.h"
#include "clang/Basic/Diagnostic.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Target/TargetData.h"
+#include "llvm/InlineAsm.h"
using namespace clang;
using namespace CodeGen;
+typedef llvm::PointerIntPair<llvm::Value*,1,bool> TryEmitResult;
+static TryEmitResult
+tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e);
+
+/// Given the address of a variable of pointer type, find the correct
+/// null to store into it.
+static llvm::Constant *getNullForVariable(llvm::Value *addr) {
+ const llvm::Type *type =
+ cast<llvm::PointerType>(addr->getType())->getElementType();
+ return llvm::ConstantPointerNull::get(cast<llvm::PointerType>(type));
+}
+
/// Emits an instance of NSConstantString representing the object.
llvm::Value *CodeGenFunction::EmitObjCStringLiteral(const ObjCStringLiteral *E)
{
@@ -55,6 +69,7 @@ static RValue AdjustRelatedResultType(CodeGenFunction &CGF,
RValue Result) {
if (!Method)
return Result;
+
if (!Method->hasRelatedResultType() ||
CGF.getContext().hasSameType(E->getType(), Method->getResultType()) ||
!Result.isScalar())
@@ -71,6 +86,18 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
// implementation vary between runtimes. We can get the receiver and
// arguments in generic code.
+ bool isDelegateInit = E->isDelegateInitCall();
+
+ // We don't retain the receiver in delegate init calls, and this is
+ // safe because the receiver value is always loaded from 'self',
+ // which we zero out. We don't want to Block_copy block receivers,
+ // though.
+ bool retainSelf =
+ (!isDelegateInit &&
+ CGM.getLangOptions().ObjCAutoRefCount &&
+ E->getMethodDecl() &&
+ E->getMethodDecl()->hasAttr<NSConsumesSelfAttr>());
+
CGObjCRuntime &Runtime = CGM.getObjCRuntime();
bool isSuperMessage = false;
bool isClassMessage = false;
@@ -80,8 +107,15 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
llvm::Value *Receiver = 0;
switch (E->getReceiverKind()) {
case ObjCMessageExpr::Instance:
- Receiver = EmitScalarExpr(E->getInstanceReceiver());
ReceiverType = E->getInstanceReceiver()->getType();
+ if (retainSelf) {
+ TryEmitResult ter = tryEmitARCRetainScalarExpr(*this,
+ E->getInstanceReceiver());
+ Receiver = ter.getPointer();
+ if (!ter.getInt())
+ Receiver = EmitARCRetainNonBlock(Receiver);
+ } else
+ Receiver = EmitScalarExpr(E->getInstanceReceiver());
break;
case ObjCMessageExpr::Class: {
@@ -92,6 +126,9 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
assert(OID && "Invalid Objective-C class message send");
Receiver = Runtime.GetClass(Builder, OID);
isClassMessage = true;
+
+ if (retainSelf)
+ Receiver = EmitARCRetainNonBlock(Receiver);
break;
}
@@ -99,6 +136,9 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
ReceiverType = E->getSuperType();
Receiver = LoadObjCSelf();
isSuperMessage = true;
+
+ if (retainSelf)
+ Receiver = EmitARCRetainNonBlock(Receiver);
break;
case ObjCMessageExpr::SuperClass:
@@ -106,14 +146,36 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
Receiver = LoadObjCSelf();
isSuperMessage = true;
isClassMessage = true;
+
+ if (retainSelf)
+ Receiver = EmitARCRetainNonBlock(Receiver);
break;
}
+ QualType ResultType =
+ E->getMethodDecl() ? E->getMethodDecl()->getResultType() : E->getType();
+
CallArgList Args;
EmitCallArgs(Args, E->getMethodDecl(), E->arg_begin(), E->arg_end());
- QualType ResultType =
- E->getMethodDecl() ? E->getMethodDecl()->getResultType() : E->getType();
+ // For delegate init calls in ARC, do an unsafe store of null into
+ // self. This represents the call taking direct ownership of that
+ // value. We have to do this after emitting the other call
+ // arguments because they might also reference self, but we don't
+ // have to worry about any of them modifying self because that would
+ // be an undefined read and write of an object in unordered
+ // expressions.
+ if (isDelegateInit) {
+ assert(getLangOptions().ObjCAutoRefCount &&
+ "delegate init calls should only be marked in ARC");
+
+ // Do an unsafe store of null into self.
+ llvm::Value *selfAddr =
+ LocalDeclMap[cast<ObjCMethodDecl>(CurCodeDecl)->getSelfDecl()];
+ assert(selfAddr && "no self entry for a delegate init call?");
+
+ Builder.CreateStore(getNullForVariable(selfAddr), selfAddr);
+ }
RValue result;
if (isSuperMessage) {
@@ -134,10 +196,54 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
Receiver, Args, OID,
E->getMethodDecl());
}
-
+
+ // For delegate init calls in ARC, implicitly store the result of
+ // the call back into self. This takes ownership of the value.
+ if (isDelegateInit) {
+ llvm::Value *selfAddr =
+ LocalDeclMap[cast<ObjCMethodDecl>(CurCodeDecl)->getSelfDecl()];
+ llvm::Value *newSelf = result.getScalarVal();
+
+ // The delegate return type isn't necessarily a matching type; in
+ // fact, it's quite likely to be 'id'.
+ const llvm::Type *selfTy =
+ cast<llvm::PointerType>(selfAddr->getType())->getElementType();
+ newSelf = Builder.CreateBitCast(newSelf, selfTy);
+
+ Builder.CreateStore(newSelf, selfAddr);
+ }
+
return AdjustRelatedResultType(*this, E, E->getMethodDecl(), result);
}
+namespace {
+struct FinishARCDealloc : EHScopeStack::Cleanup {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
+ const ObjCMethodDecl *method = cast<ObjCMethodDecl>(CGF.CurCodeDecl);
+
+ const ObjCImplDecl *impl = cast<ObjCImplDecl>(method->getDeclContext());
+ const ObjCInterfaceDecl *iface = impl->getClassInterface();
+ if (!iface->getSuperClass()) return;
+
+ bool isCategory = isa<ObjCCategoryImplDecl>(impl);
+
+ // Call [super dealloc] if we have a superclass.
+ llvm::Value *self = CGF.LoadObjCSelf();
+
+ CallArgList args;
+ CGF.CGM.getObjCRuntime().GenerateMessageSendSuper(CGF, ReturnValueSlot(),
+ CGF.getContext().VoidTy,
+ method->getSelector(),
+ iface,
+ isCategory,
+ self,
+ /*is class msg*/ false,
+ args,
+ method);
+ }
+};
+}
+
/// StartObjCMethod - Begin emission of an ObjCMethod. This generates
/// the LLVM function and sets the other context used by
/// CodeGenFunction.
@@ -164,8 +270,21 @@ void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD,
CurGD = OMD;
StartFunction(OMD, OMD->getResultType(), Fn, FI, args, StartLoc);
+
+ // In ARC, certain methods get an extra cleanup.
+ if (CGM.getLangOptions().ObjCAutoRefCount &&
+ OMD->isInstanceMethod() &&
+ OMD->getSelector().isUnarySelector()) {
+ const IdentifierInfo *ident =
+ OMD->getSelector().getIdentifierInfoForSlot(0);
+ if (ident->isStr("dealloc"))
+ EHStack.pushCleanup<FinishARCDealloc>(getARCCleanupKind());
+ }
}
+static llvm::Value *emitARCRetainLoadOfScalar(CodeGenFunction &CGF,
+ LValue lvalue, QualType type);
+
void CodeGenFunction::GenerateObjCGetterBody(ObjCIvarDecl *Ivar,
bool IsAtomic, bool IsStrong) {
LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(),
@@ -269,6 +388,9 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP,
RV = RValue::get(Builder.CreateBitCast(RV.getScalarVal(),
Types.ConvertType(PD->getType())));
EmitReturnOfRValue(RV, PD->getType());
+
+ // objc_getProperty does an autorelease, so we should suppress ours.
+ AutoreleaseResult = false;
} else {
const llvm::Triple &Triple = getContext().Target.getTriple();
QualType IVART = Ivar->getType();
@@ -346,18 +468,24 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP,
}
else {
LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(),
- Ivar, 0);
- if (PD->getType()->isReferenceType()) {
- RValue RV = RValue::get(LV.getAddress());
- EmitReturnOfRValue(RV, PD->getType());
- }
- else {
- CodeGenTypes &Types = CGM.getTypes();
- RValue RV = EmitLoadOfLValue(LV, IVART);
- RV = RValue::get(Builder.CreateBitCast(RV.getScalarVal(),
- Types.ConvertType(PD->getType())));
- EmitReturnOfRValue(RV, PD->getType());
+ Ivar, 0);
+ QualType propType = PD->getType();
+
+ llvm::Value *value;
+ if (propType->isReferenceType()) {
+ value = LV.getAddress();
+ } else {
+ // In ARC, we want to emit this retained.
+ if (getLangOptions().ObjCAutoRefCount &&
+ PD->getType()->isObjCRetainableType())
+ value = emitARCRetainLoadOfScalar(*this, LV, IVART);
+ else
+ value = EmitLoadOfLValue(LV).getScalarVal();
+
+ value = Builder.CreateBitCast(value, ConvertType(propType));
}
+
+ EmitReturnOfRValue(RValue::get(value), propType);
}
}
@@ -551,50 +679,35 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP,
FinishFunction();
}
-// FIXME: these are stolen from CGClass.cpp, which is lame.
namespace {
- struct CallArrayIvarDtor : EHScopeStack::Cleanup {
+ struct DestroyIvar : EHScopeStack::Cleanup {
+ private:
+ llvm::Value *addr;
const ObjCIvarDecl *ivar;
- llvm::Value *self;
- CallArrayIvarDtor(const ObjCIvarDecl *ivar, llvm::Value *self)
- : ivar(ivar), self(self) {}
-
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
- LValue lvalue =
- CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), self, ivar, 0);
-
- QualType type = ivar->getType();
- const ConstantArrayType *arrayType
- = CGF.getContext().getAsConstantArrayType(type);
- QualType baseType = CGF.getContext().getBaseElementType(arrayType);
- const CXXRecordDecl *classDecl = baseType->getAsCXXRecordDecl();
-
- llvm::Value *base
- = CGF.Builder.CreateBitCast(lvalue.getAddress(),
- CGF.ConvertType(baseType)->getPointerTo());
- CGF.EmitCXXAggrDestructorCall(classDecl->getDestructor(),
- arrayType, base);
+ CodeGenFunction::Destroyer &destroyer;
+ bool useEHCleanupForArray;
+ public:
+ DestroyIvar(llvm::Value *addr, const ObjCIvarDecl *ivar,
+ CodeGenFunction::Destroyer *destroyer,
+ bool useEHCleanupForArray)
+ : addr(addr), ivar(ivar), destroyer(*destroyer),
+ useEHCleanupForArray(useEHCleanupForArray) {}
+
+ void Emit(CodeGenFunction &CGF, Flags flags) {
+ LValue lvalue
+ = CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), addr, ivar, /*CVR*/ 0);
+ CGF.emitDestroy(lvalue.getAddress(), ivar->getType(), destroyer,
+ flags.isForNormalCleanup() && useEHCleanupForArray);
}
};
+}
- struct CallIvarDtor : EHScopeStack::Cleanup {
- const ObjCIvarDecl *ivar;
- llvm::Value *self;
- CallIvarDtor(const ObjCIvarDecl *ivar, llvm::Value *self)
- : ivar(ivar), self(self) {}
-
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
- LValue lvalue =
- CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), self, ivar, 0);
-
- QualType type = ivar->getType();
- const CXXRecordDecl *classDecl = type->getAsCXXRecordDecl();
-
- CGF.EmitCXXDestructorCall(classDecl->getDestructor(),
- Dtor_Complete, /*ForVirtualBase=*/false,
- lvalue.getAddress());
- }
- };
+/// Like CodeGenFunction::destroyARCStrong, but do it with a call.
+static void destroyARCStrongWithStore(CodeGenFunction &CGF,
+ llvm::Value *addr,
+ QualType type) {
+ llvm::Value *null = getNullForVariable(addr);
+ CGF.EmitARCStoreStrongCall(addr, null, /*ignored*/ true);
}
static void emitCXXDestructMethod(CodeGenFunction &CGF,
@@ -609,29 +722,26 @@ static void emitCXXDestructMethod(CodeGenFunction &CGF,
ivar; ivar = ivar->getNextIvar()) {
QualType type = ivar->getType();
- // Drill down to the base element type.
- QualType baseType = type;
- const ConstantArrayType *arrayType =
- CGF.getContext().getAsConstantArrayType(baseType);
- if (arrayType) baseType = CGF.getContext().getBaseElementType(arrayType);
-
// Check whether the ivar is a destructible type.
- QualType::DestructionKind destructKind = baseType.isDestructedType();
- assert(destructKind == type.isDestructedType());
-
- switch (destructKind) {
- case QualType::DK_none:
- continue;
-
- case QualType::DK_cxx_destructor:
- if (arrayType)
- CGF.EHStack.pushCleanup<CallArrayIvarDtor>(NormalAndEHCleanup,
- ivar, self);
- else
- CGF.EHStack.pushCleanup<CallIvarDtor>(NormalAndEHCleanup,
- ivar, self);
- break;
+ QualType::DestructionKind dtorKind = type.isDestructedType();
+ if (!dtorKind) continue;
+
+ CodeGenFunction::Destroyer *destroyer = 0;
+
+ // Use a call to objc_storeStrong to destroy strong ivars, for the
+ // general benefit of the tools.
+ if (dtorKind == QualType::DK_objc_strong_lifetime) {
+ destroyer = &destroyARCStrongWithStore;
+
+ // Otherwise use the default for the destruction kind.
+ } else {
+ destroyer = &CGF.getDestroyer(dtorKind);
}
+
+ CleanupKind cleanupKind = CGF.getCleanupKind(dtorKind);
+
+ CGF.EHStack.pushCleanup<DestroyIvar>(cleanupKind, self, ivar, destroyer,
+ cleanupKind & EHCleanup);
}
assert(scope.requiresCleanups() && "nothing to do in .cxx_destruct?");
@@ -645,6 +755,9 @@ void CodeGenFunction::GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP,
// Emit .cxx_construct.
if (ctor) {
+ // Suppress the final autorelease in ARC.
+ AutoreleaseResult = false;
+
llvm::SmallVector<CXXCtorInitializer *, 8> IvarInitializers;
for (ObjCImplementationDecl::init_const_iterator B = IMP->init_begin(),
E = IMP->init_end(); B != E; ++B) {
@@ -747,6 +860,16 @@ RValue CodeGenFunction::EmitLoadOfPropertyRefLValue(LValue LV,
llvm::Value *Receiver = LV.getPropertyRefBaseAddr();
+ if (CGM.getLangOptions().ObjCAutoRefCount) {
+ QualType receiverType;
+ if (E->isSuperReceiver())
+ receiverType = E->getSuperReceiverType();
+ else if (E->isClassReceiver())
+ receiverType = getContext().getObjCClassType();
+ else
+ receiverType = E->getBase()->getType();
+ }
+
// Accesses to 'super' follow a different code path.
if (E->isSuperReceiver())
return AdjustRelatedResultType(*this, E, method,
@@ -757,9 +880,9 @@ RValue CodeGenFunction::EmitLoadOfPropertyRefLValue(LValue LV,
const ObjCInterfaceDecl *ReceiverClass
= (E->isClassReceiver() ? E->getClassReceiver() : 0);
return AdjustRelatedResultType(*this, E, method,
- CGM.getObjCRuntime().
- GenerateMessageSend(*this, Return, ResultType, S,
- Receiver, CallArgList(), ReceiverClass));
+ CGM.getObjCRuntime().
+ GenerateMessageSend(*this, Return, ResultType, S,
+ Receiver, CallArgList(), ReceiverClass));
}
void CodeGenFunction::EmitStoreThroughPropertyRefLValue(RValue Src,
@@ -808,17 +931,17 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
return;
}
- // The local variable comes into scope immediately.
- AutoVarEmission variable = AutoVarEmission::invalid();
- if (const DeclStmt *SD = dyn_cast<DeclStmt>(S.getElement()))
- variable = EmitAutoVarAlloca(*cast<VarDecl>(SD->getSingleDecl()));
-
CGDebugInfo *DI = getDebugInfo();
if (DI) {
DI->setLocation(S.getSourceRange().getBegin());
DI->EmitRegionStart(Builder);
}
+ // The local variable comes into scope immediately.
+ AutoVarEmission variable = AutoVarEmission::invalid();
+ if (const DeclStmt *SD = dyn_cast<DeclStmt>(S.getElement()))
+ variable = EmitAutoVarAlloca(*cast<VarDecl>(SD->getSingleDecl()));
+
JumpDest LoopEnd = getJumpDestInCurrentScope("forcoll.end");
JumpDest AfterBody = getJumpDestInCurrentScope("forcoll.next");
@@ -958,6 +1081,9 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
elementLValue = EmitLValue(&tempDRE);
elementType = D->getType();
elementIsVariable = true;
+
+ if (D->isARCPseudoStrong())
+ elementLValue.getQuals().setObjCLifetime(Qualifiers::OCL_ExplicitNone);
} else {
elementLValue = LValue(); // suppress warning
elementType = cast<Expr>(S.getElement())->getType();
@@ -984,10 +1110,12 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
// Make sure we have an l-value. Yes, this gets evaluated every
// time through the loop.
- if (!elementIsVariable)
+ if (!elementIsVariable) {
elementLValue = EmitLValue(cast<Expr>(S.getElement()));
-
- EmitStoreThroughLValue(RValue::get(CurrentItem), elementLValue, elementType);
+ EmitStoreThroughLValue(RValue::get(CurrentItem), elementLValue);
+ } else {
+ EmitScalarInit(CurrentItem, elementLValue);
+ }
// If we do have an element variable, this assignment is the end of
// its initialization.
@@ -1048,7 +1176,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
llvm::Value *null = llvm::Constant::getNullValue(convertedElementType);
elementLValue = EmitLValue(cast<Expr>(S.getElement()));
- EmitStoreThroughLValue(RValue::get(null), elementLValue, elementType);
+ EmitStoreThroughLValue(RValue::get(null), elementLValue);
}
if (DI) {
@@ -1072,4 +1200,957 @@ void CodeGenFunction::EmitObjCAtSynchronizedStmt(
CGM.getObjCRuntime().EmitSynchronizedStmt(*this, S);
}
+/// Produce the code for a CK_ObjCProduceObject. Just does a
+/// primitive retain.
+llvm::Value *CodeGenFunction::EmitObjCProduceObject(QualType type,
+ llvm::Value *value) {
+ return EmitARCRetain(type, value);
+}
+
+namespace {
+ struct CallObjCRelease : EHScopeStack::Cleanup {
+ CallObjCRelease(QualType type, llvm::Value *ptr, llvm::Value *condition)
+ : type(type), ptr(ptr), condition(condition) {}
+ QualType type;
+ llvm::Value *ptr;
+ llvm::Value *condition;
+
+ void Emit(CodeGenFunction &CGF, Flags flags) {
+ llvm::Value *object;
+
+ // If we're in a conditional branch, we had to stash away in an
+ // alloca the pointer to be released.
+ llvm::BasicBlock *cont = 0;
+ if (condition) {
+ llvm::BasicBlock *release = CGF.createBasicBlock("release.yes");
+ cont = CGF.createBasicBlock("release.cont");
+
+ llvm::Value *cond = CGF.Builder.CreateLoad(condition);
+ CGF.Builder.CreateCondBr(cond, release, cont);
+ CGF.EmitBlock(release);
+ object = CGF.Builder.CreateLoad(ptr);
+ } else {
+ object = ptr;
+ }
+
+ CGF.EmitARCRelease(object, /*precise*/ true);
+
+ if (cont) CGF.EmitBlock(cont);
+ }
+ };
+}
+
+/// Produce the code for a CK_ObjCConsumeObject. Does a primitive
+/// release at the end of the full-expression.
+llvm::Value *CodeGenFunction::EmitObjCConsumeObject(QualType type,
+ llvm::Value *object) {
+ // If we're in a conditional branch, we need to make the cleanup
+ // conditional. FIXME: this really needs to be supported by the
+ // environment.
+ llvm::AllocaInst *cond;
+ llvm::Value *ptr;
+ if (isInConditionalBranch()) {
+ cond = CreateTempAlloca(Builder.getInt1Ty(), "release.cond");
+ ptr = CreateTempAlloca(object->getType(), "release.value");
+
+ // The alloca is false until we get here.
+ // FIXME: er. doesn't this need to be set at the start of the condition?
+ InitTempAlloca(cond, Builder.getFalse());
+
+ // Then it turns true.
+ Builder.CreateStore(Builder.getTrue(), cond);
+ Builder.CreateStore(object, ptr);
+ } else {
+ cond = 0;
+ ptr = object;
+ }
+
+ EHStack.pushCleanup<CallObjCRelease>(getARCCleanupKind(), type, ptr, cond);
+ return object;
+}
+
+llvm::Value *CodeGenFunction::EmitObjCExtendObjectLifetime(QualType type,
+ llvm::Value *value) {
+ return EmitARCRetainAutorelease(type, value);
+}
+
+
+static llvm::Constant *createARCRuntimeFunction(CodeGenModule &CGM,
+ const llvm::FunctionType *type,
+ llvm::StringRef fnName) {
+ llvm::Constant *fn = CGM.CreateRuntimeFunction(type, fnName);
+
+ // In -fobjc-no-arc-runtime, emit weak references to the runtime
+ // support library.
+ if (!CGM.getCodeGenOpts().ObjCRuntimeHasARC)
+ if (llvm::Function *f = dyn_cast<llvm::Function>(fn))
+ f->setLinkage(llvm::Function::ExternalWeakLinkage);
+
+ return fn;
+}
+
+/// Perform an operation having the signature
+/// i8* (i8*)
+/// where a null input causes a no-op and returns null.
+static llvm::Value *emitARCValueOperation(CodeGenFunction &CGF,
+ llvm::Value *value,
+ llvm::Constant *&fn,
+ llvm::StringRef fnName) {
+ if (isa<llvm::ConstantPointerNull>(value)) return value;
+
+ if (!fn) {
+ std::vector<llvm::Type*> args(1, CGF.Int8PtrTy);
+ const llvm::FunctionType *fnType =
+ llvm::FunctionType::get(CGF.Int8PtrTy, args, false);
+ fn = createARCRuntimeFunction(CGF.CGM, fnType, fnName);
+ }
+
+ // Cast the argument to 'id'.
+ const llvm::Type *origType = value->getType();
+ value = CGF.Builder.CreateBitCast(value, CGF.Int8PtrTy);
+
+ // Call the function.
+ llvm::CallInst *call = CGF.Builder.CreateCall(fn, value);
+ call->setDoesNotThrow();
+
+ // Cast the result back to the original type.
+ return CGF.Builder.CreateBitCast(call, origType);
+}
+
+/// Perform an operation having the following signature:
+/// i8* (i8**)
+static llvm::Value *emitARCLoadOperation(CodeGenFunction &CGF,
+ llvm::Value *addr,
+ llvm::Constant *&fn,
+ llvm::StringRef fnName) {
+ if (!fn) {
+ std::vector<llvm::Type*> args(1, CGF.Int8PtrPtrTy);
+ const llvm::FunctionType *fnType =
+ llvm::FunctionType::get(CGF.Int8PtrTy, args, false);
+ fn = createARCRuntimeFunction(CGF.CGM, fnType, fnName);
+ }
+
+ // Cast the argument to 'id*'.
+ const llvm::Type *origType = addr->getType();
+ addr = CGF.Builder.CreateBitCast(addr, CGF.Int8PtrPtrTy);
+
+ // Call the function.
+ llvm::CallInst *call = CGF.Builder.CreateCall(fn, addr);
+ call->setDoesNotThrow();
+
+ // Cast the result back to a dereference of the original type.
+ llvm::Value *result = call;
+ if (origType != CGF.Int8PtrPtrTy)
+ result = CGF.Builder.CreateBitCast(result,
+ cast<llvm::PointerType>(origType)->getElementType());
+
+ return result;
+}
+
+/// Perform an operation having the following signature:
+/// i8* (i8**, i8*)
+static llvm::Value *emitARCStoreOperation(CodeGenFunction &CGF,
+ llvm::Value *addr,
+ llvm::Value *value,
+ llvm::Constant *&fn,
+ llvm::StringRef fnName,
+ bool ignored) {
+ assert(cast<llvm::PointerType>(addr->getType())->getElementType()
+ == value->getType());
+
+ if (!fn) {
+ std::vector<llvm::Type*> argTypes(2);
+ argTypes[0] = CGF.Int8PtrPtrTy;
+ argTypes[1] = CGF.Int8PtrTy;
+
+ const llvm::FunctionType *fnType
+ = llvm::FunctionType::get(CGF.Int8PtrTy, argTypes, false);
+ fn = createARCRuntimeFunction(CGF.CGM, fnType, fnName);
+ }
+
+ const llvm::Type *origType = value->getType();
+
+ addr = CGF.Builder.CreateBitCast(addr, CGF.Int8PtrPtrTy);
+ value = CGF.Builder.CreateBitCast(value, CGF.Int8PtrTy);
+
+ llvm::CallInst *result = CGF.Builder.CreateCall2(fn, addr, value);
+ result->setDoesNotThrow();
+
+ if (ignored) return 0;
+
+ return CGF.Builder.CreateBitCast(result, origType);
+}
+
+/// Perform an operation having the following signature:
+/// void (i8**, i8**)
+static void emitARCCopyOperation(CodeGenFunction &CGF,
+ llvm::Value *dst,
+ llvm::Value *src,
+ llvm::Constant *&fn,
+ llvm::StringRef fnName) {
+ assert(dst->getType() == src->getType());
+
+ if (!fn) {
+ std::vector<llvm::Type*> argTypes(2, CGF.Int8PtrPtrTy);
+ const llvm::FunctionType *fnType
+ = llvm::FunctionType::get(CGF.Builder.getVoidTy(), argTypes, false);
+ fn = createARCRuntimeFunction(CGF.CGM, fnType, fnName);
+ }
+
+ dst = CGF.Builder.CreateBitCast(dst, CGF.Int8PtrPtrTy);
+ src = CGF.Builder.CreateBitCast(src, CGF.Int8PtrPtrTy);
+
+ llvm::CallInst *result = CGF.Builder.CreateCall2(fn, dst, src);
+ result->setDoesNotThrow();
+}
+
+/// Produce the code to do a retain. Based on the type, calls one of:
+/// call i8* @objc_retain(i8* %value)
+/// call i8* @objc_retainBlock(i8* %value)
+llvm::Value *CodeGenFunction::EmitARCRetain(QualType type, llvm::Value *value) {
+ if (type->isBlockPointerType())
+ return EmitARCRetainBlock(value);
+ else
+ return EmitARCRetainNonBlock(value);
+}
+
+/// Retain the given object, with normal retain semantics.
+/// call i8* @objc_retain(i8* %value)
+llvm::Value *CodeGenFunction::EmitARCRetainNonBlock(llvm::Value *value) {
+ return emitARCValueOperation(*this, value,
+ CGM.getARCEntrypoints().objc_retain,
+ "objc_retain");
+}
+
+/// Retain the given block, with _Block_copy semantics.
+/// call i8* @objc_retainBlock(i8* %value)
+llvm::Value *CodeGenFunction::EmitARCRetainBlock(llvm::Value *value) {
+ return emitARCValueOperation(*this, value,
+ CGM.getARCEntrypoints().objc_retainBlock,
+ "objc_retainBlock");
+}
+
+/// Retain the given object which is the result of a function call.
+/// call i8* @objc_retainAutoreleasedReturnValue(i8* %value)
+///
+/// Yes, this function name is one character away from a different
+/// call with completely different semantics.
+llvm::Value *
+CodeGenFunction::EmitARCRetainAutoreleasedReturnValue(llvm::Value *value) {
+ // Fetch the void(void) inline asm which marks that we're going to
+ // retain the autoreleased return value.
+ llvm::InlineAsm *&marker
+ = CGM.getARCEntrypoints().retainAutoreleasedReturnValueMarker;
+ if (!marker) {
+ llvm::StringRef assembly
+ = CGM.getTargetCodeGenInfo()
+ .getARCRetainAutoreleasedReturnValueMarker();
+
+ // If we have an empty assembly string, there's nothing to do.
+ if (assembly.empty()) {
+
+ // Otherwise, at -O0, build an inline asm that we're going to call
+ // in a moment.
+ } else if (CGM.getCodeGenOpts().OptimizationLevel == 0) {
+ llvm::FunctionType *type =
+ llvm::FunctionType::get(llvm::Type::getVoidTy(getLLVMContext()),
+ /*variadic*/ false);
+
+ marker = llvm::InlineAsm::get(type, assembly, "", /*sideeffects*/ true);
+
+ // If we're at -O1 and above, we don't want to litter the code
+ // with this marker yet, so leave a breadcrumb for the ARC
+ // optimizer to pick up.
+ } else {
+ llvm::NamedMDNode *metadata =
+ CGM.getModule().getOrInsertNamedMetadata(
+ "clang.arc.retainAutoreleasedReturnValueMarker");
+ assert(metadata->getNumOperands() <= 1);
+ if (metadata->getNumOperands() == 0) {
+ llvm::Value *string = llvm::MDString::get(getLLVMContext(), assembly);
+ llvm::Value *args[] = { string };
+ metadata->addOperand(llvm::MDNode::get(getLLVMContext(), args));
+ }
+ }
+ }
+
+ // Call the marker asm if we made one, which we do only at -O0.
+ if (marker) Builder.CreateCall(marker);
+
+ return emitARCValueOperation(*this, value,
+ CGM.getARCEntrypoints().objc_retainAutoreleasedReturnValue,
+ "objc_retainAutoreleasedReturnValue");
+}
+
+/// Release the given object.
+/// call void @objc_release(i8* %value)
+void CodeGenFunction::EmitARCRelease(llvm::Value *value, bool precise) {
+ if (isa<llvm::ConstantPointerNull>(value)) return;
+
+ llvm::Constant *&fn = CGM.getARCEntrypoints().objc_release;
+ if (!fn) {
+ std::vector<llvm::Type*> args(1, Int8PtrTy);
+ const llvm::FunctionType *fnType =
+ llvm::FunctionType::get(Builder.getVoidTy(), args, false);
+ fn = createARCRuntimeFunction(CGM, fnType, "objc_release");
+ }
+
+ // Cast the argument to 'id'.
+ value = Builder.CreateBitCast(value, Int8PtrTy);
+
+ // Call objc_release.
+ llvm::CallInst *call = Builder.CreateCall(fn, value);
+ call->setDoesNotThrow();
+
+ if (!precise) {
+ llvm::SmallVector<llvm::Value*,1> args;
+ call->setMetadata("clang.imprecise_release",
+ llvm::MDNode::get(Builder.getContext(), args));
+ }
+}
+
+/// Store into a strong object. Always calls this:
+/// call void @objc_storeStrong(i8** %addr, i8* %value)
+llvm::Value *CodeGenFunction::EmitARCStoreStrongCall(llvm::Value *addr,
+ llvm::Value *value,
+ bool ignored) {
+ assert(cast<llvm::PointerType>(addr->getType())->getElementType()
+ == value->getType());
+
+ llvm::Constant *&fn = CGM.getARCEntrypoints().objc_storeStrong;
+ if (!fn) {
+ llvm::Type *argTypes[] = { Int8PtrPtrTy, Int8PtrTy };
+ const llvm::FunctionType *fnType
+ = llvm::FunctionType::get(Builder.getVoidTy(), argTypes, false);
+ fn = createARCRuntimeFunction(CGM, fnType, "objc_storeStrong");
+ }
+
+ addr = Builder.CreateBitCast(addr, Int8PtrPtrTy);
+ llvm::Value *castValue = Builder.CreateBitCast(value, Int8PtrTy);
+
+ Builder.CreateCall2(fn, addr, castValue)->setDoesNotThrow();
+
+ if (ignored) return 0;
+ return value;
+}
+
+/// Store into a strong object. Sometimes calls this:
+/// call void @objc_storeStrong(i8** %addr, i8* %value)
+/// Other times, breaks it down into components.
+llvm::Value *CodeGenFunction::EmitARCStoreStrong(LValue dst,
+ llvm::Value *newValue,
+ bool ignored) {
+ QualType type = dst.getType();
+ bool isBlock = type->isBlockPointerType();
+
+ // Use a store barrier at -O0 unless this is a block type or the
+ // lvalue is inadequately aligned.
+ if (shouldUseFusedARCCalls() &&
+ !isBlock &&
+ !(dst.getAlignment() && dst.getAlignment() < PointerAlignInBytes)) {
+ return EmitARCStoreStrongCall(dst.getAddress(), newValue, ignored);
+ }
+
+ // Otherwise, split it out.
+
+ // Retain the new value.
+ newValue = EmitARCRetain(type, newValue);
+
+ // Read the old value.
+ llvm::Value *oldValue = EmitLoadOfScalar(dst);
+
+ // Store. We do this before the release so that any deallocs won't
+ // see the old value.
+ EmitStoreOfScalar(newValue, dst);
+
+ // Finally, release the old value.
+ EmitARCRelease(oldValue, /*precise*/ false);
+
+ return newValue;
+}
+
+/// Autorelease the given object.
+/// call i8* @objc_autorelease(i8* %value)
+llvm::Value *CodeGenFunction::EmitARCAutorelease(llvm::Value *value) {
+ return emitARCValueOperation(*this, value,
+ CGM.getARCEntrypoints().objc_autorelease,
+ "objc_autorelease");
+}
+
+/// Autorelease the given object.
+/// call i8* @objc_autoreleaseReturnValue(i8* %value)
+llvm::Value *
+CodeGenFunction::EmitARCAutoreleaseReturnValue(llvm::Value *value) {
+ return emitARCValueOperation(*this, value,
+ CGM.getARCEntrypoints().objc_autoreleaseReturnValue,
+ "objc_autoreleaseReturnValue");
+}
+
+/// Do a fused retain/autorelease of the given object.
+/// call i8* @objc_retainAutoreleaseReturnValue(i8* %value)
+llvm::Value *
+CodeGenFunction::EmitARCRetainAutoreleaseReturnValue(llvm::Value *value) {
+ return emitARCValueOperation(*this, value,
+ CGM.getARCEntrypoints().objc_retainAutoreleaseReturnValue,
+ "objc_retainAutoreleaseReturnValue");
+}
+
+/// Do a fused retain/autorelease of the given object.
+/// call i8* @objc_retainAutorelease(i8* %value)
+/// or
+/// %retain = call i8* @objc_retainBlock(i8* %value)
+/// call i8* @objc_autorelease(i8* %retain)
+llvm::Value *CodeGenFunction::EmitARCRetainAutorelease(QualType type,
+ llvm::Value *value) {
+ if (!type->isBlockPointerType())
+ return EmitARCRetainAutoreleaseNonBlock(value);
+
+ if (isa<llvm::ConstantPointerNull>(value)) return value;
+
+ const llvm::Type *origType = value->getType();
+ value = Builder.CreateBitCast(value, Int8PtrTy);
+ value = EmitARCRetainBlock(value);
+ value = EmitARCAutorelease(value);
+ return Builder.CreateBitCast(value, origType);
+}
+
+/// Do a fused retain/autorelease of the given object.
+/// call i8* @objc_retainAutorelease(i8* %value)
+llvm::Value *
+CodeGenFunction::EmitARCRetainAutoreleaseNonBlock(llvm::Value *value) {
+ return emitARCValueOperation(*this, value,
+ CGM.getARCEntrypoints().objc_retainAutorelease,
+ "objc_retainAutorelease");
+}
+
+/// i8* @objc_loadWeak(i8** %addr)
+/// Essentially objc_autorelease(objc_loadWeakRetained(addr)).
+llvm::Value *CodeGenFunction::EmitARCLoadWeak(llvm::Value *addr) {
+ return emitARCLoadOperation(*this, addr,
+ CGM.getARCEntrypoints().objc_loadWeak,
+ "objc_loadWeak");
+}
+
+/// i8* @objc_loadWeakRetained(i8** %addr)
+llvm::Value *CodeGenFunction::EmitARCLoadWeakRetained(llvm::Value *addr) {
+ return emitARCLoadOperation(*this, addr,
+ CGM.getARCEntrypoints().objc_loadWeakRetained,
+ "objc_loadWeakRetained");
+}
+
+/// i8* @objc_storeWeak(i8** %addr, i8* %value)
+/// Returns %value.
+llvm::Value *CodeGenFunction::EmitARCStoreWeak(llvm::Value *addr,
+ llvm::Value *value,
+ bool ignored) {
+ return emitARCStoreOperation(*this, addr, value,
+ CGM.getARCEntrypoints().objc_storeWeak,
+ "objc_storeWeak", ignored);
+}
+
+/// i8* @objc_initWeak(i8** %addr, i8* %value)
+/// Returns %value. %addr is known to not have a current weak entry.
+/// Essentially equivalent to:
+/// *addr = nil; objc_storeWeak(addr, value);
+void CodeGenFunction::EmitARCInitWeak(llvm::Value *addr, llvm::Value *value) {
+ // If we're initializing to null, just write null to memory; no need
+ // to get the runtime involved. But don't do this if optimization
+ // is enabled, because accounting for this would make the optimizer
+ // much more complicated.
+ if (isa<llvm::ConstantPointerNull>(value) &&
+ CGM.getCodeGenOpts().OptimizationLevel == 0) {
+ Builder.CreateStore(value, addr);
+ return;
+ }
+
+ emitARCStoreOperation(*this, addr, value,
+ CGM.getARCEntrypoints().objc_initWeak,
+ "objc_initWeak", /*ignored*/ true);
+}
+
+/// void @objc_destroyWeak(i8** %addr)
+/// Essentially objc_storeWeak(addr, nil).
+void CodeGenFunction::EmitARCDestroyWeak(llvm::Value *addr) {
+ llvm::Constant *&fn = CGM.getARCEntrypoints().objc_destroyWeak;
+ if (!fn) {
+ std::vector<llvm::Type*> args(1, Int8PtrPtrTy);
+ const llvm::FunctionType *fnType =
+ llvm::FunctionType::get(Builder.getVoidTy(), args, false);
+ fn = createARCRuntimeFunction(CGM, fnType, "objc_destroyWeak");
+ }
+
+ // Cast the argument to 'id*'.
+ addr = Builder.CreateBitCast(addr, Int8PtrPtrTy);
+
+ llvm::CallInst *call = Builder.CreateCall(fn, addr);
+ call->setDoesNotThrow();
+}
+
+/// void @objc_moveWeak(i8** %dest, i8** %src)
+/// Disregards the current value in %dest. Leaves %src pointing to nothing.
+/// Essentially (objc_copyWeak(dest, src), objc_destroyWeak(src)).
+void CodeGenFunction::EmitARCMoveWeak(llvm::Value *dst, llvm::Value *src) {
+ emitARCCopyOperation(*this, dst, src,
+ CGM.getARCEntrypoints().objc_moveWeak,
+ "objc_moveWeak");
+}
+
+/// void @objc_copyWeak(i8** %dest, i8** %src)
+/// Disregards the current value in %dest. Essentially
+/// objc_release(objc_initWeak(dest, objc_readWeakRetained(src)))
+void CodeGenFunction::EmitARCCopyWeak(llvm::Value *dst, llvm::Value *src) {
+ emitARCCopyOperation(*this, dst, src,
+ CGM.getARCEntrypoints().objc_copyWeak,
+ "objc_copyWeak");
+}
+
+/// Produce the code to do a objc_autoreleasepool_push.
+/// call i8* @objc_autoreleasePoolPush(void)
+llvm::Value *CodeGenFunction::EmitObjCAutoreleasePoolPush() {
+ llvm::Constant *&fn = CGM.getRREntrypoints().objc_autoreleasePoolPush;
+ if (!fn) {
+ const llvm::FunctionType *fnType =
+ llvm::FunctionType::get(Int8PtrTy, false);
+ fn = createARCRuntimeFunction(CGM, fnType, "objc_autoreleasePoolPush");
+ }
+
+ llvm::CallInst *call = Builder.CreateCall(fn);
+ call->setDoesNotThrow();
+
+ return call;
+}
+
+/// Produce the code to do a primitive release.
+/// call void @objc_autoreleasePoolPop(i8* %ptr)
+void CodeGenFunction::EmitObjCAutoreleasePoolPop(llvm::Value *value) {
+ assert(value->getType() == Int8PtrTy);
+
+ llvm::Constant *&fn = CGM.getRREntrypoints().objc_autoreleasePoolPop;
+ if (!fn) {
+ std::vector<llvm::Type*> args(1, Int8PtrTy);
+ const llvm::FunctionType *fnType =
+ llvm::FunctionType::get(Builder.getVoidTy(), args, false);
+
+ // We don't want to use a weak import here; instead we should not
+ // fall into this path.
+ fn = createARCRuntimeFunction(CGM, fnType, "objc_autoreleasePoolPop");
+ }
+
+ llvm::CallInst *call = Builder.CreateCall(fn, value);
+ call->setDoesNotThrow();
+}
+
+/// Produce the code to do an MRR version objc_autoreleasepool_push.
+/// Which is: [[NSAutoreleasePool alloc] init];
+/// Where alloc is declared as: + (id) alloc; in NSAutoreleasePool class.
+/// init is declared as: - (id) init; in its NSObject super class.
+///
+llvm::Value *CodeGenFunction::EmitObjCMRRAutoreleasePoolPush() {
+ CGObjCRuntime &Runtime = CGM.getObjCRuntime();
+ llvm::Value *Receiver = Runtime.EmitNSAutoreleasePoolClassRef(Builder);
+ // [NSAutoreleasePool alloc]
+ IdentifierInfo *II = &CGM.getContext().Idents.get("alloc");
+ Selector AllocSel = getContext().Selectors.getSelector(0, &II);
+ CallArgList Args;
+ RValue AllocRV =
+ Runtime.GenerateMessageSend(*this, ReturnValueSlot(),
+ getContext().getObjCIdType(),
+ AllocSel, Receiver, Args);
+
+ // [Receiver init]
+ Receiver = AllocRV.getScalarVal();
+ II = &CGM.getContext().Idents.get("init");
+ Selector InitSel = getContext().Selectors.getSelector(0, &II);
+ RValue InitRV =
+ Runtime.GenerateMessageSend(*this, ReturnValueSlot(),
+ getContext().getObjCIdType(),
+ InitSel, Receiver, Args);
+ return InitRV.getScalarVal();
+}
+
+/// Produce the code to do a primitive release.
+/// [tmp drain];
+void CodeGenFunction::EmitObjCMRRAutoreleasePoolPop(llvm::Value *Arg) {
+ IdentifierInfo *II = &CGM.getContext().Idents.get("drain");
+ Selector DrainSel = getContext().Selectors.getSelector(0, &II);
+ CallArgList Args;
+ CGM.getObjCRuntime().GenerateMessageSend(*this, ReturnValueSlot(),
+ getContext().VoidTy, DrainSel, Arg, Args);
+}
+
+void CodeGenFunction::destroyARCStrongPrecise(CodeGenFunction &CGF,
+ llvm::Value *addr,
+ QualType type) {
+ llvm::Value *ptr = CGF.Builder.CreateLoad(addr, "strongdestroy");
+ CGF.EmitARCRelease(ptr, /*precise*/ true);
+}
+
+void CodeGenFunction::destroyARCStrongImprecise(CodeGenFunction &CGF,
+ llvm::Value *addr,
+ QualType type) {
+ llvm::Value *ptr = CGF.Builder.CreateLoad(addr, "strongdestroy");
+ CGF.EmitARCRelease(ptr, /*precise*/ false);
+}
+
+void CodeGenFunction::destroyARCWeak(CodeGenFunction &CGF,
+ llvm::Value *addr,
+ QualType type) {
+ CGF.EmitARCDestroyWeak(addr);
+}
+
+namespace {
+ struct CallObjCAutoreleasePoolObject : EHScopeStack::Cleanup {
+ llvm::Value *Token;
+
+ CallObjCAutoreleasePoolObject(llvm::Value *token) : Token(token) {}
+
+ void Emit(CodeGenFunction &CGF, Flags flags) {
+ CGF.EmitObjCAutoreleasePoolPop(Token);
+ }
+ };
+ struct CallObjCMRRAutoreleasePoolObject : EHScopeStack::Cleanup {
+ llvm::Value *Token;
+
+ CallObjCMRRAutoreleasePoolObject(llvm::Value *token) : Token(token) {}
+
+ void Emit(CodeGenFunction &CGF, Flags flags) {
+ CGF.EmitObjCMRRAutoreleasePoolPop(Token);
+ }
+ };
+}
+
+void CodeGenFunction::EmitObjCAutoreleasePoolCleanup(llvm::Value *Ptr) {
+ if (CGM.getLangOptions().ObjCAutoRefCount)
+ EHStack.pushCleanup<CallObjCAutoreleasePoolObject>(NormalCleanup, Ptr);
+ else
+ EHStack.pushCleanup<CallObjCMRRAutoreleasePoolObject>(NormalCleanup, Ptr);
+}
+
+static TryEmitResult tryEmitARCRetainLoadOfScalar(CodeGenFunction &CGF,
+ LValue lvalue,
+ QualType type) {
+ switch (type.getObjCLifetime()) {
+ case Qualifiers::OCL_None:
+ case Qualifiers::OCL_ExplicitNone:
+ case Qualifiers::OCL_Strong:
+ case Qualifiers::OCL_Autoreleasing:
+ return TryEmitResult(CGF.EmitLoadOfLValue(lvalue).getScalarVal(),
+ false);
+
+ case Qualifiers::OCL_Weak:
+ return TryEmitResult(CGF.EmitARCLoadWeakRetained(lvalue.getAddress()),
+ true);
+ }
+
+ llvm_unreachable("impossible lifetime!");
+ return TryEmitResult();
+}
+
+static TryEmitResult tryEmitARCRetainLoadOfScalar(CodeGenFunction &CGF,
+ const Expr *e) {
+ e = e->IgnoreParens();
+ QualType type = e->getType();
+
+ // As a very special optimization, in ARC++, if the l-value is the
+ // result of a non-volatile assignment, do a simple retain of the
+ // result of the call to objc_storeWeak instead of reloading.
+ if (CGF.getLangOptions().CPlusPlus &&
+ !type.isVolatileQualified() &&
+ type.getObjCLifetime() == Qualifiers::OCL_Weak &&
+ isa<BinaryOperator>(e) &&
+ cast<BinaryOperator>(e)->getOpcode() == BO_Assign)
+ return TryEmitResult(CGF.EmitScalarExpr(e), false);
+
+ return tryEmitARCRetainLoadOfScalar(CGF, CGF.EmitLValue(e), type);
+}
+
+static llvm::Value *emitARCRetainAfterCall(CodeGenFunction &CGF,
+ llvm::Value *value);
+
+/// Given that the given expression is some sort of call (which does
+/// not return retained), emit a retain following it.
+static llvm::Value *emitARCRetainCall(CodeGenFunction &CGF, const Expr *e) {
+ llvm::Value *value = CGF.EmitScalarExpr(e);
+ return emitARCRetainAfterCall(CGF, value);
+}
+
+static llvm::Value *emitARCRetainAfterCall(CodeGenFunction &CGF,
+ llvm::Value *value) {
+ if (llvm::CallInst *call = dyn_cast<llvm::CallInst>(value)) {
+ CGBuilderTy::InsertPoint ip = CGF.Builder.saveIP();
+
+ // Place the retain immediately following the call.
+ CGF.Builder.SetInsertPoint(call->getParent(),
+ ++llvm::BasicBlock::iterator(call));
+ value = CGF.EmitARCRetainAutoreleasedReturnValue(value);
+
+ CGF.Builder.restoreIP(ip);
+ return value;
+ } else if (llvm::InvokeInst *invoke = dyn_cast<llvm::InvokeInst>(value)) {
+ CGBuilderTy::InsertPoint ip = CGF.Builder.saveIP();
+
+ // Place the retain at the beginning of the normal destination block.
+ llvm::BasicBlock *BB = invoke->getNormalDest();
+ CGF.Builder.SetInsertPoint(BB, BB->begin());
+ value = CGF.EmitARCRetainAutoreleasedReturnValue(value);
+
+ CGF.Builder.restoreIP(ip);
+ return value;
+
+ // Bitcasts can arise because of related-result returns. Rewrite
+ // the operand.
+ } else if (llvm::BitCastInst *bitcast = dyn_cast<llvm::BitCastInst>(value)) {
+ llvm::Value *operand = bitcast->getOperand(0);
+ operand = emitARCRetainAfterCall(CGF, operand);
+ bitcast->setOperand(0, operand);
+ return bitcast;
+
+ // Generic fall-back case.
+ } else {
+ // Retain using the non-block variant: we never need to do a copy
+ // of a block that's been returned to us.
+ return CGF.EmitARCRetainNonBlock(value);
+ }
+}
+
+static TryEmitResult
+tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e) {
+ // The desired result type, if it differs from the type of the
+ // ultimate opaque expression.
+ const llvm::Type *resultType = 0;
+
+ // If we're loading retained from a __strong xvalue, we can avoid
+ // an extra retain/release pair by zeroing out the source of this
+ // "move" operation.
+ if (e->isXValue() && !e->getType().isConstQualified() &&
+ e->getType().getObjCLifetime() == Qualifiers::OCL_Strong) {
+ // Emit the lvalue
+ LValue lv = CGF.EmitLValue(e);
+
+ // Load the object pointer and cast it to the appropriate type.
+ QualType exprType = e->getType();
+ llvm::Value *result = CGF.EmitLoadOfLValue(lv).getScalarVal();
+
+ if (resultType)
+ result = CGF.Builder.CreateBitCast(result, resultType);
+
+ // Set the source pointer to NULL.
+ llvm::Value *null
+ = llvm::ConstantPointerNull::get(
+ cast<llvm::PointerType>(CGF.ConvertType(exprType)));
+ CGF.EmitStoreOfScalar(null, lv);
+
+ return TryEmitResult(result, true);
+ }
+
+ while (true) {
+ e = e->IgnoreParens();
+
+ // There's a break at the end of this if-chain; anything
+ // that wants to keep looping has to explicitly continue.
+ if (const CastExpr *ce = dyn_cast<CastExpr>(e)) {
+ switch (ce->getCastKind()) {
+ // No-op casts don't change the type, so we just ignore them.
+ case CK_NoOp:
+ e = ce->getSubExpr();
+ continue;
+
+ case CK_LValueToRValue: {
+ TryEmitResult loadResult
+ = tryEmitARCRetainLoadOfScalar(CGF, ce->getSubExpr());
+ if (resultType) {
+ llvm::Value *value = loadResult.getPointer();
+ value = CGF.Builder.CreateBitCast(value, resultType);
+ loadResult.setPointer(value);
+ }
+ return loadResult;
+ }
+
+ // These casts can change the type, so remember that and
+ // soldier on. We only need to remember the outermost such
+ // cast, though.
+ case CK_AnyPointerToObjCPointerCast:
+ case CK_AnyPointerToBlockPointerCast:
+ case CK_BitCast:
+ if (!resultType)
+ resultType = CGF.ConvertType(ce->getType());
+ e = ce->getSubExpr();
+ assert(e->getType()->hasPointerRepresentation());
+ continue;
+
+ // For consumptions, just emit the subexpression and thus elide
+ // the retain/release pair.
+ case CK_ObjCConsumeObject: {
+ llvm::Value *result = CGF.EmitScalarExpr(ce->getSubExpr());
+ if (resultType) result = CGF.Builder.CreateBitCast(result, resultType);
+ return TryEmitResult(result, true);
+ }
+
+ // For reclaims, emit the subexpression as a retained call and
+ // skip the consumption.
+ case CK_ObjCReclaimReturnedObject: {
+ llvm::Value *result = emitARCRetainCall(CGF, ce->getSubExpr());
+ if (resultType) result = CGF.Builder.CreateBitCast(result, resultType);
+ return TryEmitResult(result, true);
+ }
+
+ case CK_GetObjCProperty: {
+ llvm::Value *result = emitARCRetainCall(CGF, ce);
+ if (resultType) result = CGF.Builder.CreateBitCast(result, resultType);
+ return TryEmitResult(result, true);
+ }
+
+ default:
+ break;
+ }
+
+ // Skip __extension__.
+ } else if (const UnaryOperator *op = dyn_cast<UnaryOperator>(e)) {
+ if (op->getOpcode() == UO_Extension) {
+ e = op->getSubExpr();
+ continue;
+ }
+
+ // For calls and message sends, use the retained-call logic.
+ // Delegate inits are a special case in that they're the only
+ // returns-retained expression that *isn't* surrounded by
+ // a consume.
+ } else if (isa<CallExpr>(e) ||
+ (isa<ObjCMessageExpr>(e) &&
+ !cast<ObjCMessageExpr>(e)->isDelegateInitCall())) {
+ llvm::Value *result = emitARCRetainCall(CGF, e);
+ if (resultType) result = CGF.Builder.CreateBitCast(result, resultType);
+ return TryEmitResult(result, true);
+ }
+
+ // Conservatively halt the search at any other expression kind.
+ break;
+ }
+
+ // We didn't find an obvious production, so emit what we've got and
+ // tell the caller that we didn't manage to retain.
+ llvm::Value *result = CGF.EmitScalarExpr(e);
+ if (resultType) result = CGF.Builder.CreateBitCast(result, resultType);
+ return TryEmitResult(result, false);
+}
+
+static llvm::Value *emitARCRetainLoadOfScalar(CodeGenFunction &CGF,
+ LValue lvalue,
+ QualType type) {
+ TryEmitResult result = tryEmitARCRetainLoadOfScalar(CGF, lvalue, type);
+ llvm::Value *value = result.getPointer();
+ if (!result.getInt())
+ value = CGF.EmitARCRetain(type, value);
+ return value;
+}
+
+/// EmitARCRetainScalarExpr - Semantically equivalent to
+/// EmitARCRetainObject(e->getType(), EmitScalarExpr(e)), but making a
+/// best-effort attempt to peephole expressions that naturally produce
+/// retained objects.
+llvm::Value *CodeGenFunction::EmitARCRetainScalarExpr(const Expr *e) {
+ TryEmitResult result = tryEmitARCRetainScalarExpr(*this, e);
+ llvm::Value *value = result.getPointer();
+ if (!result.getInt())
+ value = EmitARCRetain(e->getType(), value);
+ return value;
+}
+
+llvm::Value *
+CodeGenFunction::EmitARCRetainAutoreleaseScalarExpr(const Expr *e) {
+ TryEmitResult result = tryEmitARCRetainScalarExpr(*this, e);
+ llvm::Value *value = result.getPointer();
+ if (result.getInt())
+ value = EmitARCAutorelease(value);
+ else
+ value = EmitARCRetainAutorelease(e->getType(), value);
+ return value;
+}
+
+std::pair<LValue,llvm::Value*>
+CodeGenFunction::EmitARCStoreStrong(const BinaryOperator *e,
+ bool ignored) {
+ // Evaluate the RHS first.
+ TryEmitResult result = tryEmitARCRetainScalarExpr(*this, e->getRHS());
+ llvm::Value *value = result.getPointer();
+
+ LValue lvalue = EmitLValue(e->getLHS());
+
+ // If the RHS was emitted retained, expand this.
+ if (result.getInt()) {
+ llvm::Value *oldValue =
+ EmitLoadOfScalar(lvalue.getAddress(), lvalue.isVolatileQualified(),
+ lvalue.getAlignment(), e->getType(),
+ lvalue.getTBAAInfo());
+ EmitStoreOfScalar(value, lvalue.getAddress(),
+ lvalue.isVolatileQualified(), lvalue.getAlignment(),
+ e->getType(), lvalue.getTBAAInfo());
+ EmitARCRelease(oldValue, /*precise*/ false);
+ } else {
+ value = EmitARCStoreStrong(lvalue, value, ignored);
+ }
+
+ return std::pair<LValue,llvm::Value*>(lvalue, value);
+}
+
+std::pair<LValue,llvm::Value*>
+CodeGenFunction::EmitARCStoreAutoreleasing(const BinaryOperator *e) {
+ llvm::Value *value = EmitARCRetainAutoreleaseScalarExpr(e->getRHS());
+ LValue lvalue = EmitLValue(e->getLHS());
+
+ EmitStoreOfScalar(value, lvalue.getAddress(),
+ lvalue.isVolatileQualified(), lvalue.getAlignment(),
+ e->getType(), lvalue.getTBAAInfo());
+
+ return std::pair<LValue,llvm::Value*>(lvalue, value);
+}
+
+void CodeGenFunction::EmitObjCAutoreleasePoolStmt(
+ const ObjCAutoreleasePoolStmt &ARPS) {
+ const Stmt *subStmt = ARPS.getSubStmt();
+ const CompoundStmt &S = cast<CompoundStmt>(*subStmt);
+
+ CGDebugInfo *DI = getDebugInfo();
+ if (DI) {
+ DI->setLocation(S.getLBracLoc());
+ DI->EmitRegionStart(Builder);
+ }
+
+ // Keep track of the current cleanup stack depth.
+ RunCleanupsScope Scope(*this);
+ if (CGM.getCodeGenOpts().ObjCRuntimeHasARC) {
+ llvm::Value *token = EmitObjCAutoreleasePoolPush();
+ EHStack.pushCleanup<CallObjCAutoreleasePoolObject>(NormalCleanup, token);
+ } else {
+ llvm::Value *token = EmitObjCMRRAutoreleasePoolPush();
+ EHStack.pushCleanup<CallObjCMRRAutoreleasePoolObject>(NormalCleanup, token);
+ }
+
+ for (CompoundStmt::const_body_iterator I = S.body_begin(),
+ E = S.body_end(); I != E; ++I)
+ EmitStmt(*I);
+
+ if (DI) {
+ DI->setLocation(S.getRBracLoc());
+ DI->EmitRegionEnd(Builder);
+ }
+}
+
+/// EmitExtendGCLifetime - Given a pointer to an Objective-C object,
+/// make sure it survives garbage collection until this point.
+void CodeGenFunction::EmitExtendGCLifetime(llvm::Value *object) {
+ // We just use an inline assembly.
+ llvm::Type *paramTypes[] = { VoidPtrTy };
+ llvm::FunctionType *extenderType
+ = llvm::FunctionType::get(VoidTy, paramTypes, /*variadic*/ false);
+ llvm::Value *extender
+ = llvm::InlineAsm::get(extenderType,
+ /* assembly */ "",
+ /* constraints */ "r",
+ /* side effects */ true);
+
+ object = Builder.CreateBitCast(object, VoidPtrTy);
+ Builder.CreateCall(extender, object)->setDoesNotThrow();
+}
+
CGObjCRuntime::~CGObjCRuntime() {}
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index f0993c5dadbb..61027feb5cb9 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -50,7 +50,7 @@ namespace {
/// avoids constructing the type more than once if it's used more than once.
class LazyRuntimeFunction {
CodeGenModule *CGM;
- std::vector<const llvm::Type*> ArgTys;
+ std::vector<llvm::Type*> ArgTys;
const char *FunctionName;
llvm::Constant *Function;
public:
@@ -63,14 +63,14 @@ class LazyRuntimeFunction {
/// of the arguments.
END_WITH_NULL
void init(CodeGenModule *Mod, const char *name,
- const llvm::Type *RetTy, ...) {
+ llvm::Type *RetTy, ...) {
CGM =Mod;
FunctionName = name;
Function = 0;
ArgTys.clear();
va_list Args;
va_start(Args, RetTy);
- while (const llvm::Type *ArgTy = va_arg(Args, const llvm::Type*))
+ while (llvm::Type *ArgTy = va_arg(Args, llvm::Type*))
ArgTys.push_back(ArgTy);
va_end(Args);
// Push the return type on at the end so we can pop it off easily
@@ -118,24 +118,24 @@ protected:
/// LLVM type for selectors. Opaque pointer (i8*) unless a header declaring
/// SEL is included in a header somewhere, in which case it will be whatever
/// type is declared in that header, most likely {i8*, i8*}.
- const llvm::PointerType *SelectorTy;
+ llvm::PointerType *SelectorTy;
/// LLVM i8 type. Cached here to avoid repeatedly getting it in all of the
/// places where it's used
const llvm::IntegerType *Int8Ty;
/// Pointer to i8 - LLVM type of char*, for all of the places where the
/// runtime needs to deal with C strings.
- const llvm::PointerType *PtrToInt8Ty;
+ llvm::PointerType *PtrToInt8Ty;
/// Instance Method Pointer type. This is a pointer to a function that takes,
/// at a minimum, an object and a selector, and is the generic type for
/// Objective-C methods. Due to differences between variadic / non-variadic
/// calling conventions, it must always be cast to the correct type before
/// actually being used.
- const llvm::PointerType *IMPTy;
+ llvm::PointerType *IMPTy;
/// Type of an untyped Objective-C object. Clang treats id as a built-in type
/// when compiling Objective-C code, so this may be an opaque pointer (i8*),
/// but if the runtime header declaring it is included then it may be a
/// pointer to a structure.
- const llvm::PointerType *IdTy;
+ llvm::PointerType *IdTy;
/// Pointer to a pointer to an Objective-C object. Used in the new ABI
/// message lookup function and some GC-related functions.
const llvm::PointerType *PtrToIdTy;
@@ -143,15 +143,15 @@ protected:
/// call Objective-C methods.
CanQualType ASTIdTy;
/// LLVM type for C int type.
- const llvm::IntegerType *IntTy;
+ llvm::IntegerType *IntTy;
/// LLVM type for an opaque pointer. This is identical to PtrToInt8Ty, but is
/// used in the code to document the difference between i8* meaning a pointer
/// to a C string and i8* meaning a pointer to some opaque type.
- const llvm::PointerType *PtrTy;
+ llvm::PointerType *PtrTy;
/// LLVM type for C long type. The runtime uses this in a lot of places where
/// it should be using intptr_t, but we can't fix this without breaking
/// compatibility with GCC...
- const llvm::IntegerType *LongTy;
+ llvm::IntegerType *LongTy;
/// LLVM type for C size_t. Used in various runtime data structures.
const llvm::IntegerType *SizeTy;
/// LLVM type for C ptrdiff_t. Mainly used in property accessor functions.
@@ -392,6 +392,9 @@ private:
/// Emits a reference to a class. This allows the linker to object if there
/// is no class of the matching name.
void EmitClassRef(const std::string &className);
+ /// Emits a pointer to the named class
+ llvm::Value *GetClassNamed(CGBuilderTy &Builder, const std::string &Name,
+ bool isWeak);
protected:
/// Looks up the method for sending a message to the specified object. This
/// mechanism differs between the GCC and GNU runtimes, so this method must be
@@ -484,6 +487,7 @@ public:
virtual llvm::Value *EmitIvarOffset(CodeGenFunction &CGF,
const ObjCInterfaceDecl *Interface,
const ObjCIvarDecl *Ivar);
+ virtual llvm::Value *EmitNSAutoreleasePoolClassRef(CGBuilderTy &Builder);
virtual llvm::Constant *BuildGCBlockLayout(CodeGenModule &CGM,
const CGBlockInfo &blockInfo) {
return NULLPtr;
@@ -527,7 +531,7 @@ protected:
CGBuilderTy &Builder = CGF.Builder;
llvm::Value *lookupArgs[] = {EnforceType(Builder, ObjCSuper,
PtrToObjCSuperTy), cmd};
- return Builder.CreateCall(MsgLookupSuperFn, lookupArgs, lookupArgs+2);
+ return Builder.CreateCall(MsgLookupSuperFn, lookupArgs);
}
public:
CGObjCGCC(CodeGenModule &Mod) : CGObjCGNU(Mod, 8, 2) {
@@ -596,15 +600,14 @@ class CGObjCGNUstep : public CGObjCGNU {
CGBuilderTy &Builder = CGF.Builder;
llvm::Value *lookupArgs[] = {ObjCSuper, cmd};
- llvm::CallInst *slot = Builder.CreateCall(SlotLookupSuperFn, lookupArgs,
- lookupArgs+2);
+ llvm::CallInst *slot = Builder.CreateCall(SlotLookupSuperFn, lookupArgs);
slot->setOnlyReadsMemory();
return Builder.CreateLoad(Builder.CreateStructGEP(slot, 4));
}
public:
CGObjCGNUstep(CodeGenModule &Mod) : CGObjCGNU(Mod, 9, 3) {
- llvm::StructType *SlotStructTy = llvm::StructType::get(VMContext, PtrTy,
+ llvm::StructType *SlotStructTy = llvm::StructType::get(PtrTy,
PtrTy, PtrTy, IntTy, IMPTy, NULL);
SlotTy = llvm::PointerType::getUnqual(SlotStructTy);
// Slot_t objc_msg_lookup_sender(id *receiver, SEL selector, id sender);
@@ -615,7 +618,7 @@ class CGObjCGNUstep : public CGObjCGNU {
PtrToObjCSuperTy, SelectorTy, NULL);
// If we're in ObjC++ mode, then we want to make
if (CGM.getLangOptions().CPlusPlus) {
- const llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
+ llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
// void *__cxa_begin_catch(void *e)
EnterCatchFn.init(&CGM, "__cxa_begin_catch", PtrTy, PtrTy, NULL);
// void __cxa_end_catch(void)
@@ -705,10 +708,10 @@ CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion,
}
PtrToIdTy = llvm::PointerType::getUnqual(IdTy);
- ObjCSuperTy = llvm::StructType::get(VMContext, IdTy, IdTy, NULL);
+ ObjCSuperTy = llvm::StructType::get(IdTy, IdTy, NULL);
PtrToObjCSuperTy = llvm::PointerType::getUnqual(ObjCSuperTy);
- const llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
+ llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
// void objc_exception_throw(id);
ExceptionThrowFn.init(&CGM, "objc_exception_throw", VoidTy, IdTy, NULL);
@@ -736,16 +739,19 @@ CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion,
PtrDiffTy, BoolTy, BoolTy, NULL);
// IMP type
- const llvm::Type *IMPArgs[] = { IdTy, SelectorTy };
+ llvm::Type *IMPArgs[] = { IdTy, SelectorTy };
IMPTy = llvm::PointerType::getUnqual(llvm::FunctionType::get(IdTy, IMPArgs,
true));
+ const LangOptions &Opts = CGM.getLangOptions();
+ if ((Opts.getGCMode() != LangOptions::NonGC) || Opts.ObjCAutoRefCount)
+ RuntimeVersion = 10;
+
// Don't bother initialising the GC stuff unless we're compiling in GC mode
- if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC) {
+ if (Opts.getGCMode() != LangOptions::NonGC) {
// This is a bit of an hack. We should sort this out by having a proper
// CGObjCGNUstep subclass for GC, but we may want to really support the old
// ABI and GC added in ObjectiveC2.framework, so we fudge it a bit for now
- RuntimeVersion = 10;
// Get selectors needed in GC mode
RetainSel = GetNullarySelector("retain", CGM.getContext());
ReleaseSel = GetNullarySelector("release", CGM.getContext());
@@ -772,24 +778,38 @@ CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion,
}
}
-// This has to perform the lookup every time, since posing and related
-// techniques can modify the name -> class mapping.
-llvm::Value *CGObjCGNU::GetClass(CGBuilderTy &Builder,
- const ObjCInterfaceDecl *OID) {
- llvm::Value *ClassName = CGM.GetAddrOfConstantCString(OID->getNameAsString());
+llvm::Value *CGObjCGNU::GetClassNamed(CGBuilderTy &Builder,
+ const std::string &Name,
+ bool isWeak) {
+ llvm::Value *ClassName = CGM.GetAddrOfConstantCString(Name);
// With the incompatible ABI, this will need to be replaced with a direct
// reference to the class symbol. For the compatible nonfragile ABI we are
// still performing this lookup at run time but emitting the symbol for the
// class externally so that we can make the switch later.
- EmitClassRef(OID->getNameAsString());
+ //
+ // Libobjc2 contains an LLVM pass that replaces calls to objc_lookup_class
+ // with memoized versions or with static references if it's safe to do so.
+ if (!isWeak)
+ EmitClassRef(Name);
ClassName = Builder.CreateStructGEP(ClassName, 0);
+ llvm::Type *ArgTys[] = { PtrToInt8Ty };
llvm::Constant *ClassLookupFn =
- CGM.CreateRuntimeFunction(llvm::FunctionType::get(IdTy, PtrToInt8Ty, true),
+ CGM.CreateRuntimeFunction(llvm::FunctionType::get(IdTy, ArgTys, true),
"objc_lookup_class");
return Builder.CreateCall(ClassLookupFn, ClassName);
}
+// This has to perform the lookup every time, since posing and related
+// techniques can modify the name -> class mapping.
+llvm::Value *CGObjCGNU::GetClass(CGBuilderTy &Builder,
+ const ObjCInterfaceDecl *OID) {
+ return GetClassNamed(Builder, OID->getNameAsString(), OID->isWeakImported());
+}
+llvm::Value *CGObjCGNU::EmitNSAutoreleasePoolClassRef(CGBuilderTy &Builder) {
+ return GetClassNamed(Builder, "NSAutoreleasePool", false);
+}
+
llvm::Value *CGObjCGNU::GetSelector(CGBuilderTy &Builder, Selector Sel,
const std::string &TypeEncoding, bool lval) {
@@ -908,7 +928,7 @@ llvm::Constant *CGObjCGNU::GetEHType(QualType T) {
fields.push_back(Vtable);
fields.push_back(typeName);
llvm::Constant *TI =
- MakeGlobal(llvm::StructType::get(VMContext, PtrToInt8Ty, PtrToInt8Ty,
+ MakeGlobal(llvm::StructType::get(PtrToInt8Ty, PtrToInt8Ty,
NULL), fields, "__objc_eh_typeinfo_" + className,
llvm::GlobalValue::LinkOnceODRLinkage);
return llvm::ConstantExpr::getBitCast(TI, PtrToInt8Ty);
@@ -929,7 +949,7 @@ llvm::Constant *CGObjCGNU::GenerateConstantString(const StringLiteral *SL) {
Ivars.push_back(MakeConstantString(Str));
Ivars.push_back(llvm::ConstantInt::get(IntTy, Str.size()));
llvm::Constant *ObjCStr = MakeGlobal(
- llvm::StructType::get(VMContext, PtrToInt8Ty, PtrToInt8Ty, IntTy, NULL),
+ llvm::StructType::get(PtrToInt8Ty, PtrToInt8Ty, IntTy, NULL),
Ivars, ".objc_str");
ObjCStr = llvm::ConstantExpr::getBitCast(ObjCStr, PtrToInt8Ty);
ObjCStrings[Str] = ObjCStr;
@@ -969,7 +989,7 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF,
ActualArgs.add(RValue::get(EnforceType(Builder, Receiver, IdTy)), ASTIdTy);
ActualArgs.add(RValue::get(cmd), CGF.getContext().getObjCSelType());
- ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end());
+ ActualArgs.addFrom(CallArgs);
CodeGenTypes &Types = CGM.getTypes();
const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs,
@@ -979,11 +999,13 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF,
if (isCategoryImpl) {
llvm::Constant *classLookupFunction = 0;
if (IsClassMessage) {
+ llvm::Type *ArgTys[] = { PtrTy };
classLookupFunction = CGM.CreateRuntimeFunction(llvm::FunctionType::get(
- IdTy, PtrTy, true), "objc_get_meta_class");
+ IdTy, ArgTys, true), "objc_get_meta_class");
} else {
+ llvm::Type *ArgTys[] = { PtrTy };
classLookupFunction = CGM.CreateRuntimeFunction(llvm::FunctionType::get(
- IdTy, PtrTy, true), "objc_get_class");
+ IdTy, ArgTys, true), "objc_get_class");
}
ReceiverClass = Builder.CreateCall(classLookupFunction,
MakeConstantString(Class->getNameAsString()));
@@ -1012,13 +1034,13 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF,
// Cast the pointer to a simplified version of the class structure
ReceiverClass = Builder.CreateBitCast(ReceiverClass,
llvm::PointerType::getUnqual(
- llvm::StructType::get(VMContext, IdTy, IdTy, NULL)));
+ llvm::StructType::get(IdTy, IdTy, NULL)));
// Get the superclass pointer
ReceiverClass = Builder.CreateStructGEP(ReceiverClass, 1);
// Load the superclass pointer
ReceiverClass = Builder.CreateLoad(ReceiverClass);
// Construct the structure used to look up the IMP
- llvm::StructType *ObjCSuperTy = llvm::StructType::get(VMContext,
+ llvm::StructType *ObjCSuperTy = llvm::StructType::get(
Receiver->getType(), IdTy, NULL);
llvm::Value *ObjCSuper = Builder.CreateAlloca(ObjCSuperTy);
@@ -1121,7 +1143,7 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
CallArgList ActualArgs;
ActualArgs.add(RValue::get(Receiver), ASTIdTy);
ActualArgs.add(RValue::get(cmd), CGF.getContext().getObjCSelType());
- ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end());
+ ActualArgs.addFrom(CallArgs);
CodeGenTypes &Types = CGM.getTypes();
const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs,
@@ -1187,7 +1209,7 @@ llvm::Constant *CGObjCGNU::GenerateMethodList(const llvm::StringRef &ClassName,
if (MethodSels.empty())
return NULLPtr;
// Get the method structure type.
- llvm::StructType *ObjCMethodTy = llvm::StructType::get(VMContext,
+ llvm::StructType *ObjCMethodTy = llvm::StructType::get(
PtrToInt8Ty, // Really a selector, but the runtime creates it us.
PtrToInt8Ty, // Method types
IMPTy, //Method pointer
@@ -1217,18 +1239,14 @@ llvm::Constant *CGObjCGNU::GenerateMethodList(const llvm::StringRef &ClassName,
Methods);
// Structure containing list pointer, array and array count
- llvm::SmallVector<const llvm::Type*, 16> ObjCMethodListFields;
- llvm::PATypeHolder OpaqueNextTy = llvm::OpaqueType::get(VMContext);
- llvm::Type *NextPtrTy = llvm::PointerType::getUnqual(OpaqueNextTy);
- llvm::StructType *ObjCMethodListTy = llvm::StructType::get(VMContext,
+ llvm::StructType *ObjCMethodListTy =
+ llvm::StructType::createNamed(VMContext, "");
+ llvm::Type *NextPtrTy = llvm::PointerType::getUnqual(ObjCMethodListTy);
+ ObjCMethodListTy->setBody(
NextPtrTy,
IntTy,
ObjCMethodArrayTy,
NULL);
- // Refine next pointer type to concrete type
- llvm::cast<llvm::OpaqueType>(
- OpaqueNextTy.get())->refineAbstractTypeTo(ObjCMethodListTy);
- ObjCMethodListTy = llvm::cast<llvm::StructType>(OpaqueNextTy.get());
Methods.clear();
Methods.push_back(llvm::ConstantPointerNull::get(
@@ -1249,7 +1267,7 @@ llvm::Constant *CGObjCGNU::GenerateIvarList(
if (IvarNames.size() == 0)
return NULLPtr;
// Get the method structure type.
- llvm::StructType *ObjCIvarTy = llvm::StructType::get(VMContext,
+ llvm::StructType *ObjCIvarTy = llvm::StructType::get(
PtrToInt8Ty,
PtrToInt8Ty,
IntTy,
@@ -1273,7 +1291,7 @@ llvm::Constant *CGObjCGNU::GenerateIvarList(
Elements.push_back(llvm::ConstantInt::get(IntTy, (int)IvarNames.size()));
Elements.push_back(llvm::ConstantArray::get(ObjCIvarArrayTy, Ivars));
// Structure containing array and array count
- llvm::StructType *ObjCIvarListTy = llvm::StructType::get(VMContext, IntTy,
+ llvm::StructType *ObjCIvarListTy = llvm::StructType::get(IntTy,
ObjCIvarArrayTy,
NULL);
@@ -1302,7 +1320,7 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure(
// Fields marked New ABI are part of the GNUstep runtime. We emit them
// anyway; the classes will still work with the GNU runtime, they will just
// be ignored.
- llvm::StructType *ClassTy = llvm::StructType::get(VMContext,
+ llvm::StructType *ClassTy = llvm::StructType::get(
PtrToInt8Ty, // class_pointer
PtrToInt8Ty, // super_class
PtrToInt8Ty, // name
@@ -1359,7 +1377,7 @@ llvm::Constant *CGObjCGNU::GenerateProtocolMethodList(
const llvm::SmallVectorImpl<llvm::Constant *> &MethodNames,
const llvm::SmallVectorImpl<llvm::Constant *> &MethodTypes) {
// Get the method structure type.
- llvm::StructType *ObjCMethodDescTy = llvm::StructType::get(VMContext,
+ llvm::StructType *ObjCMethodDescTy = llvm::StructType::get(
PtrToInt8Ty, // Really a selector, but the runtime does the casting for us.
PtrToInt8Ty,
NULL);
@@ -1375,7 +1393,7 @@ llvm::Constant *CGObjCGNU::GenerateProtocolMethodList(
MethodNames.size());
llvm::Constant *Array = llvm::ConstantArray::get(ObjCMethodArrayTy,
Methods);
- llvm::StructType *ObjCMethodDescListTy = llvm::StructType::get(VMContext,
+ llvm::StructType *ObjCMethodDescListTy = llvm::StructType::get(
IntTy, ObjCMethodArrayTy, NULL);
Methods.clear();
Methods.push_back(llvm::ConstantInt::get(IntTy, MethodNames.size()));
@@ -1388,7 +1406,7 @@ llvm::Constant *CGObjCGNU::GenerateProtocolList(
const llvm::SmallVectorImpl<std::string> &Protocols) {
llvm::ArrayType *ProtocolArrayTy = llvm::ArrayType::get(PtrToInt8Ty,
Protocols.size());
- llvm::StructType *ProtocolListTy = llvm::StructType::get(VMContext,
+ llvm::StructType *ProtocolListTy = llvm::StructType::get(
PtrTy, //Should be a recurisve pointer, but it's always NULL here.
SizeTy,
ProtocolArrayTy,
@@ -1435,7 +1453,7 @@ llvm::Constant *CGObjCGNU::GenerateEmptyProtocol(
GenerateProtocolMethodList(EmptyConstantVector, EmptyConstantVector);
// Protocols are objects containing lists of the methods implemented and
// protocols adopted.
- llvm::StructType *ProtocolTy = llvm::StructType::get(VMContext, IdTy,
+ llvm::StructType *ProtocolTy = llvm::StructType::get(IdTy,
PtrToInt8Ty,
ProtocolList->getType(),
MethodList->getType(),
@@ -1521,7 +1539,7 @@ void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) {
// The isSynthesized value is always set to 0 in a protocol. It exists to
// simplify the runtime library by allowing it to use the same data
// structures for protocol metadata everywhere.
- llvm::StructType *PropertyMetadataTy = llvm::StructType::get(VMContext,
+ llvm::StructType *PropertyMetadataTy = llvm::StructType::get(
PtrToInt8Ty, Int8Ty, Int8Ty, PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty,
PtrToInt8Ty, NULL);
std::vector<llvm::Constant*> Properties;
@@ -1573,7 +1591,7 @@ void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) {
{llvm::ConstantInt::get(IntTy, Properties.size()), NULLPtr, PropertyArray};
llvm::Constant *PropertyListInit =
- llvm::ConstantStruct::get(VMContext, PropertyListInitFields, 3, false);
+ llvm::ConstantStruct::getAnon(PropertyListInitFields);
llvm::Constant *PropertyList = new llvm::GlobalVariable(TheModule,
PropertyListInit->getType(), false, llvm::GlobalValue::InternalLinkage,
PropertyListInit, ".objc_property_list");
@@ -1586,7 +1604,7 @@ void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) {
OptionalPropertyArray };
llvm::Constant *OptionalPropertyListInit =
- llvm::ConstantStruct::get(VMContext, OptionalPropertyListInitFields, 3, false);
+ llvm::ConstantStruct::getAnon(OptionalPropertyListInitFields);
llvm::Constant *OptionalPropertyList = new llvm::GlobalVariable(TheModule,
OptionalPropertyListInit->getType(), false,
llvm::GlobalValue::InternalLinkage, OptionalPropertyListInit,
@@ -1594,7 +1612,7 @@ void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) {
// Protocols are objects containing lists of the methods implemented and
// protocols adopted.
- llvm::StructType *ProtocolTy = llvm::StructType::get(VMContext, IdTy,
+ llvm::StructType *ProtocolTy = llvm::StructType::get(IdTy,
PtrToInt8Ty,
ProtocolList->getType(),
InstanceMethodList->getType(),
@@ -1641,7 +1659,7 @@ void CGObjCGNU::GenerateProtocolHolderCategory(void) {
// Protocol list
llvm::ArrayType *ProtocolArrayTy = llvm::ArrayType::get(PtrTy,
ExistingProtocols.size());
- llvm::StructType *ProtocolListTy = llvm::StructType::get(VMContext,
+ llvm::StructType *ProtocolListTy = llvm::StructType::get(
PtrTy, //Should be a recurisve pointer, but it's always NULL here.
SizeTy,
ProtocolArrayTy,
@@ -1664,7 +1682,7 @@ void CGObjCGNU::GenerateProtocolHolderCategory(void) {
Elements.push_back(llvm::ConstantExpr::getBitCast(MakeGlobal(ProtocolListTy,
ProtocolElements, ".objc_protocol_list"), PtrTy));
Categories.push_back(llvm::ConstantExpr::getBitCast(
- MakeGlobal(llvm::StructType::get(VMContext, PtrToInt8Ty, PtrToInt8Ty,
+ MakeGlobal(llvm::StructType::get(PtrToInt8Ty, PtrToInt8Ty,
PtrTy, PtrTy, PtrTy, NULL), Elements), PtrTy));
}
@@ -1718,7 +1736,7 @@ void CGObjCGNU::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
Elements.push_back(llvm::ConstantExpr::getBitCast(
GenerateProtocolList(Protocols), PtrTy));
Categories.push_back(llvm::ConstantExpr::getBitCast(
- MakeGlobal(llvm::StructType::get(VMContext, PtrToInt8Ty, PtrToInt8Ty,
+ MakeGlobal(llvm::StructType::get(PtrToInt8Ty, PtrToInt8Ty,
PtrTy, PtrTy, PtrTy, NULL), Elements), PtrTy));
}
@@ -1729,7 +1747,7 @@ llvm::Constant *CGObjCGNU::GeneratePropertyList(const ObjCImplementationDecl *OI
//
// Property metadata: name, attributes, isSynthesized, setter name, setter
// types, getter name, getter types.
- llvm::StructType *PropertyMetadataTy = llvm::StructType::get(VMContext,
+ llvm::StructType *PropertyMetadataTy = llvm::StructType::get(
PtrToInt8Ty, Int8Ty, Int8Ty, PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty,
PtrToInt8Ty, NULL);
std::vector<llvm::Constant*> Properties;
@@ -1788,7 +1806,7 @@ llvm::Constant *CGObjCGNU::GeneratePropertyList(const ObjCImplementationDecl *OI
{llvm::ConstantInt::get(IntTy, Properties.size()), NULLPtr, PropertyArray};
llvm::Constant *PropertyListInit =
- llvm::ConstantStruct::get(VMContext, PropertyListInitFields, 3, false);
+ llvm::ConstantStruct::getAnon(PropertyListInitFields);
return new llvm::GlobalVariable(TheModule, PropertyListInit->getType(), false,
llvm::GlobalValue::InternalLinkage, PropertyListInit,
".objc_property_list");
@@ -1859,13 +1877,25 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
if (CGM.getContext().getLangOptions().ObjCNonFragileABI) {
Offset = BaseOffset - superInstanceSize;
}
- IvarOffsets.push_back(
- llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), Offset));
- IvarOffsetValues.push_back(new llvm::GlobalVariable(TheModule, IntTy,
+ llvm::Constant *OffsetValue = llvm::ConstantInt::get(IntTy, Offset);
+ // Create the direct offset value
+ std::string OffsetName = "__objc_ivar_offset_value_" + ClassName +"." +
+ IVD->getNameAsString();
+ llvm::GlobalVariable *OffsetVar = TheModule.getGlobalVariable(OffsetName);
+ if (OffsetVar) {
+ OffsetVar->setInitializer(OffsetValue);
+ // If this is the real definition, change its linkage type so that
+ // different modules will use this one, rather than their private
+ // copy.
+ OffsetVar->setLinkage(llvm::GlobalValue::ExternalLinkage);
+ } else
+ OffsetVar = new llvm::GlobalVariable(TheModule, IntTy,
false, llvm::GlobalValue::ExternalLinkage,
- llvm::ConstantInt::get(IntTy, Offset),
+ OffsetValue,
"__objc_ivar_offset_value_" + ClassName +"." +
- IVD->getNameAsString()));
+ IVD->getNameAsString());
+ IvarOffsets.push_back(OffsetValue);
+ IvarOffsetValues.push_back(OffsetVar);
}
llvm::GlobalVariable *IvarOffsetArray =
MakeGlobalArray(PtrToIntTy, IvarOffsetValues, ".ivar.offsets");
@@ -2005,18 +2035,12 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
const llvm::StructType *SelStructTy = dyn_cast<llvm::StructType>(
SelectorTy->getElementType());
- const llvm::Type *SelStructPtrTy = SelectorTy;
+ llvm::Type *SelStructPtrTy = SelectorTy;
if (SelStructTy == 0) {
- SelStructTy = llvm::StructType::get(VMContext, PtrToInt8Ty,
- PtrToInt8Ty, NULL);
+ SelStructTy = llvm::StructType::get(PtrToInt8Ty, PtrToInt8Ty, NULL);
SelStructPtrTy = llvm::PointerType::getUnqual(SelStructTy);
}
- // Name the ObjC types to make the IR a bit easier to read
- TheModule.addTypeName(".objc_selector", SelStructPtrTy);
- TheModule.addTypeName(".objc_id", IdTy);
- TheModule.addTypeName(".objc_imp", IMPTy);
-
std::vector<llvm::Constant*> Elements;
llvm::Constant *Statics = NULLPtr;
// Generate statics list:
@@ -2034,7 +2058,7 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
Elements.push_back(llvm::ConstantArray::get(StaticsArrayTy,
ConstantStrings));
llvm::StructType *StaticsListTy =
- llvm::StructType::get(VMContext, PtrToInt8Ty, StaticsArrayTy, NULL);
+ llvm::StructType::get(PtrToInt8Ty, StaticsArrayTy, NULL);
llvm::Type *StaticsListPtrTy =
llvm::PointerType::getUnqual(StaticsListTy);
Statics = MakeGlobal(StaticsListTy, Elements, ".objc_statics");
@@ -2049,8 +2073,7 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
// Array of classes, categories, and constant objects
llvm::ArrayType *ClassListTy = llvm::ArrayType::get(PtrToInt8Ty,
Classes.size() + Categories.size() + 2);
- llvm::StructType *SymTabTy = llvm::StructType::get(VMContext,
- LongTy, SelStructPtrTy,
+ llvm::StructType *SymTabTy = llvm::StructType::get(LongTy, SelStructPtrTy,
llvm::Type::getInt16Ty(VMContext),
llvm::Type::getInt16Ty(VMContext),
ClassListTy, NULL);
@@ -2132,10 +2155,9 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
// The symbol table is contained in a module which has some version-checking
// constants
- llvm::StructType * ModuleTy = llvm::StructType::get(VMContext, LongTy, LongTy,
+ llvm::StructType * ModuleTy = llvm::StructType::get(LongTy, LongTy,
PtrToInt8Ty, llvm::PointerType::getUnqual(SymTabTy),
- (CGM.getLangOptions().getGCMode() == LangOptions::NonGC) ? NULL : IntTy,
- NULL);
+ (RuntimeVersion >= 10) ? IntTy : NULL, NULL);
Elements.clear();
// Runtime version, used for ABI compatibility checking.
Elements.push_back(llvm::ConstantInt::get(LongTy, RuntimeVersion));
@@ -2154,14 +2176,21 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
Elements.push_back(MakeConstantString(path, ".objc_source_file_name"));
Elements.push_back(SymTab);
- switch (CGM.getLangOptions().getGCMode()) {
- case LangOptions::GCOnly:
+ if (RuntimeVersion >= 10)
+ switch (CGM.getLangOptions().getGCMode()) {
+ case LangOptions::GCOnly:
Elements.push_back(llvm::ConstantInt::get(IntTy, 2));
- case LangOptions::NonGC:
break;
- case LangOptions::HybridGC:
- Elements.push_back(llvm::ConstantInt::get(IntTy, 1));
- }
+ case LangOptions::NonGC:
+ if (CGM.getLangOptions().ObjCAutoRefCount)
+ Elements.push_back(llvm::ConstantInt::get(IntTy, 1));
+ else
+ Elements.push_back(llvm::ConstantInt::get(IntTy, 0));
+ break;
+ case LangOptions::HybridGC:
+ Elements.push_back(llvm::ConstantInt::get(IntTy, 1));
+ break;
+ }
llvm::Value *Module = MakeGlobal(ModuleTy, Elements);
@@ -2176,9 +2205,9 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
CGBuilderTy Builder(VMContext);
Builder.SetInsertPoint(EntryBB);
+ llvm::Type *ArgTys[] = { llvm::PointerType::getUnqual(ModuleTy) };
llvm::FunctionType *FT =
- llvm::FunctionType::get(Builder.getVoidTy(),
- llvm::PointerType::getUnqual(ModuleTy), true);
+ llvm::FunctionType::get(Builder.getVoidTy(), ArgTys, true);
llvm::Value *Register = CGM.CreateRuntimeFunction(FT, "__objc_exec_class");
Builder.CreateCall(Register, Module);
Builder.CreateRetVoid();
@@ -2280,8 +2309,8 @@ void CGObjCGNU::EmitThrowStmt(CodeGenFunction &CGF,
CGF.Builder.CreateCall(ExceptionThrowFn, ExceptionAsObject);
CGF.Builder.CreateUnreachable();
} else {
- CGF.Builder.CreateInvoke(ExceptionThrowFn, UnwindBB, UnwindBB, &ExceptionAsObject,
- &ExceptionAsObject+1);
+ CGF.Builder.CreateInvoke(ExceptionThrowFn, UnwindBB, UnwindBB,
+ ExceptionAsObject);
}
// Clear the insertion point to indicate we are in unreachable code.
CGF.Builder.ClearInsertionPoint();
@@ -2422,10 +2451,19 @@ llvm::Value *CGObjCGNU::EmitIvarOffset(CodeGenFunction &CGF,
const ObjCIvarDecl *Ivar) {
if (CGM.getLangOptions().ObjCNonFragileABI) {
Interface = FindIvarInterface(CGM.getContext(), Interface, Ivar);
- return CGF.Builder.CreateZExtOrBitCast(
- CGF.Builder.CreateLoad(CGF.Builder.CreateLoad(
- ObjCIvarOffsetVariable(Interface, Ivar), false, "ivar")),
- PtrDiffTy);
+ if (RuntimeVersion < 10)
+ return CGF.Builder.CreateZExtOrBitCast(
+ CGF.Builder.CreateLoad(CGF.Builder.CreateLoad(
+ ObjCIvarOffsetVariable(Interface, Ivar), false, "ivar")),
+ PtrDiffTy);
+ std::string name = "__objc_ivar_offset_value_" +
+ Interface->getNameAsString() +"." + Ivar->getNameAsString();
+ llvm::Value *Offset = TheModule.getGlobalVariable(name);
+ if (!Offset)
+ Offset = new llvm::GlobalVariable(TheModule, IntTy,
+ false, llvm::GlobalValue::CommonLinkage,
+ 0, name);
+ return CGF.Builder.CreateLoad(Offset);
}
uint64_t Offset = ComputeIvarBaseOffset(CGF.CGM, Interface, Ivar);
return llvm::ConstantInt::get(PtrDiffTy, Offset, "ivar");
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index 8c3e9a36e307..010b9e174e46 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -63,10 +63,13 @@ private:
/// The default messenger, used for sends whose ABI is unchanged from
/// the all-integer/pointer case.
llvm::Constant *getMessageSendFn() const {
- const llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
+ // Add the non-lazy-bind attribute, since objc_msgSend is likely to
+ // be called a lot.
+ llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
params, true),
- "objc_msgSend");
+ "objc_msgSend",
+ llvm::Attribute::NonLazyBind);
}
/// void objc_msgSend_stret (id, SEL, ...)
@@ -75,7 +78,7 @@ private:
/// by indirect reference in the first argument, and therefore the
/// self and selector parameters are shifted over by one.
llvm::Constant *getMessageSendStretFn() const {
- const llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
+ llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.VoidTy,
params, true),
"objc_msgSend_stret");
@@ -88,7 +91,7 @@ private:
/// floating-point stack; without a special entrypoint, the nil case
/// would be unbalanced.
llvm::Constant *getMessageSendFpretFn() const {
- const llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
+ llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(
llvm::Type::getDoubleTy(VMContext),
params, true),
@@ -102,7 +105,7 @@ private:
/// semantics. The class passed is the superclass of the current
/// class.
llvm::Constant *getMessageSendSuperFn() const {
- const llvm::Type *params[] = { SuperPtrTy, SelectorPtrTy };
+ llvm::Type *params[] = { SuperPtrTy, SelectorPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
params, true),
"objc_msgSendSuper");
@@ -113,7 +116,7 @@ private:
/// A slightly different messenger used for super calls. The class
/// passed is the current class.
llvm::Constant *getMessageSendSuperFn2() const {
- const llvm::Type *params[] = { SuperPtrTy, SelectorPtrTy };
+ llvm::Type *params[] = { SuperPtrTy, SelectorPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
params, true),
"objc_msgSendSuper2");
@@ -124,7 +127,7 @@ private:
///
/// The messenger used for super calls which return an aggregate indirectly.
llvm::Constant *getMessageSendSuperStretFn() const {
- const llvm::Type *params[] = { Int8PtrTy, SuperPtrTy, SelectorPtrTy };
+ llvm::Type *params[] = { Int8PtrTy, SuperPtrTy, SelectorPtrTy };
return CGM.CreateRuntimeFunction(
llvm::FunctionType::get(CGM.VoidTy, params, true),
"objc_msgSendSuper_stret");
@@ -135,7 +138,7 @@ private:
///
/// objc_msgSendSuper_stret with the super2 semantics.
llvm::Constant *getMessageSendSuperStretFn2() const {
- const llvm::Type *params[] = { Int8PtrTy, SuperPtrTy, SelectorPtrTy };
+ llvm::Type *params[] = { Int8PtrTy, SuperPtrTy, SelectorPtrTy };
return CGM.CreateRuntimeFunction(
llvm::FunctionType::get(CGM.VoidTy, params, true),
"objc_msgSendSuper2_stret");
@@ -155,20 +158,20 @@ protected:
CodeGen::CodeGenModule &CGM;
public:
- const llvm::Type *ShortTy, *IntTy, *LongTy, *LongLongTy;
- const llvm::Type *Int8PtrTy;
+ llvm::Type *ShortTy, *IntTy, *LongTy, *LongLongTy;
+ llvm::Type *Int8PtrTy;
/// ObjectPtrTy - LLVM type for object handles (typeof(id))
- const llvm::Type *ObjectPtrTy;
+ llvm::Type *ObjectPtrTy;
/// PtrObjectPtrTy - LLVM type for id *
- const llvm::Type *PtrObjectPtrTy;
+ llvm::Type *PtrObjectPtrTy;
/// SelectorPtrTy - LLVM type for selector handles (typeof(SEL))
- const llvm::Type *SelectorPtrTy;
+ llvm::Type *SelectorPtrTy;
/// ProtocolPtrTy - LLVM type for external protocol handles
/// (typeof(Protocol))
- const llvm::Type *ExternalProtocolPtrTy;
+ llvm::Type *ExternalProtocolPtrTy;
// SuperCTy - clang type for struct objc_super.
QualType SuperCTy;
@@ -176,28 +179,28 @@ public:
QualType SuperPtrCTy;
/// SuperTy - LLVM type for struct objc_super.
- const llvm::StructType *SuperTy;
+ llvm::StructType *SuperTy;
/// SuperPtrTy - LLVM type for struct objc_super *.
- const llvm::Type *SuperPtrTy;
+ llvm::Type *SuperPtrTy;
/// PropertyTy - LLVM type for struct objc_property (struct _prop_t
/// in GCC parlance).
- const llvm::StructType *PropertyTy;
+ llvm::StructType *PropertyTy;
/// PropertyListTy - LLVM type for struct objc_property_list
/// (_prop_list_t in GCC parlance).
- const llvm::StructType *PropertyListTy;
+ llvm::StructType *PropertyListTy;
/// PropertyListPtrTy - LLVM type for struct objc_property_list*.
- const llvm::Type *PropertyListPtrTy;
+ llvm::Type *PropertyListPtrTy;
// MethodTy - LLVM type for struct objc_method.
- const llvm::StructType *MethodTy;
+ llvm::StructType *MethodTy;
/// CacheTy - LLVM type for struct objc_cache.
- const llvm::Type *CacheTy;
+ llvm::Type *CacheTy;
/// CachePtrTy - LLVM type for struct objc_cache *.
- const llvm::Type *CachePtrTy;
-
+ llvm::Type *CachePtrTy;
+
llvm::Constant *getGetPropertyFn() {
CodeGen::CodeGenTypes &Types = CGM.getTypes();
ASTContext &Ctx = CGM.getContext();
@@ -270,7 +273,7 @@ public:
/// GcReadWeakFn -- LLVM objc_read_weak (id *src) function.
llvm::Constant *getGcReadWeakFn() {
// id objc_read_weak (id *)
- const llvm::Type *args[] = { ObjectPtrTy->getPointerTo() };
+ llvm::Type *args[] = { ObjectPtrTy->getPointerTo() };
llvm::FunctionType *FTy =
llvm::FunctionType::get(ObjectPtrTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_read_weak");
@@ -279,7 +282,7 @@ public:
/// GcAssignWeakFn -- LLVM objc_assign_weak function.
llvm::Constant *getGcAssignWeakFn() {
// id objc_assign_weak (id, id *)
- const llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo() };
+ llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo() };
llvm::FunctionType *FTy =
llvm::FunctionType::get(ObjectPtrTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_assign_weak");
@@ -288,7 +291,7 @@ public:
/// GcAssignGlobalFn -- LLVM objc_assign_global function.
llvm::Constant *getGcAssignGlobalFn() {
// id objc_assign_global(id, id *)
- const llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo() };
+ llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo() };
llvm::FunctionType *FTy =
llvm::FunctionType::get(ObjectPtrTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_assign_global");
@@ -297,7 +300,7 @@ public:
/// GcAssignThreadLocalFn -- LLVM objc_assign_threadlocal function.
llvm::Constant *getGcAssignThreadLocalFn() {
// id objc_assign_threadlocal(id src, id * dest)
- const llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo() };
+ llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo() };
llvm::FunctionType *FTy =
llvm::FunctionType::get(ObjectPtrTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_assign_threadlocal");
@@ -306,8 +309,8 @@ public:
/// GcAssignIvarFn -- LLVM objc_assign_ivar function.
llvm::Constant *getGcAssignIvarFn() {
// id objc_assign_ivar(id, id *, ptrdiff_t)
- const llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo(),
- CGM.PtrDiffTy };
+ llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo(),
+ CGM.PtrDiffTy };
llvm::FunctionType *FTy =
llvm::FunctionType::get(ObjectPtrTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_assign_ivar");
@@ -316,7 +319,7 @@ public:
/// GcMemmoveCollectableFn -- LLVM objc_memmove_collectable function.
llvm::Constant *GcMemmoveCollectableFn() {
// void *objc_memmove_collectable(void *dst, const void *src, size_t size)
- const llvm::Type *args[] = { Int8PtrTy, Int8PtrTy, LongTy };
+ llvm::Type *args[] = { Int8PtrTy, Int8PtrTy, LongTy };
llvm::FunctionType *FTy = llvm::FunctionType::get(Int8PtrTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_memmove_collectable");
}
@@ -324,7 +327,7 @@ public:
/// GcAssignStrongCastFn -- LLVM objc_assign_strongCast function.
llvm::Constant *getGcAssignStrongCastFn() {
// id objc_assign_strongCast(id, id *)
- const llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo() };
+ llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo() };
llvm::FunctionType *FTy =
llvm::FunctionType::get(ObjectPtrTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_assign_strongCast");
@@ -333,7 +336,7 @@ public:
/// ExceptionThrowFn - LLVM objc_exception_throw function.
llvm::Constant *getExceptionThrowFn() {
// void objc_exception_throw(id)
- const llvm::Type *args[] = { ObjectPtrTy };
+ llvm::Type *args[] = { ObjectPtrTy };
llvm::FunctionType *FTy =
llvm::FunctionType::get(CGM.VoidTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_exception_throw");
@@ -349,7 +352,7 @@ public:
/// SyncEnterFn - LLVM object_sync_enter function.
llvm::Constant *getSyncEnterFn() {
// void objc_sync_enter (id)
- const llvm::Type *args[] = { ObjectPtrTy };
+ llvm::Type *args[] = { ObjectPtrTy };
llvm::FunctionType *FTy =
llvm::FunctionType::get(CGM.VoidTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_sync_enter");
@@ -358,7 +361,7 @@ public:
/// SyncExitFn - LLVM object_sync_exit function.
llvm::Constant *getSyncExitFn() {
// void objc_sync_exit (id)
- const llvm::Type *args[] = { ObjectPtrTy };
+ llvm::Type *args[] = { ObjectPtrTy };
llvm::FunctionType *FTy =
llvm::FunctionType::get(CGM.VoidTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_sync_exit");
@@ -397,62 +400,62 @@ public:
class ObjCTypesHelper : public ObjCCommonTypesHelper {
public:
/// SymtabTy - LLVM type for struct objc_symtab.
- const llvm::StructType *SymtabTy;
+ llvm::StructType *SymtabTy;
/// SymtabPtrTy - LLVM type for struct objc_symtab *.
- const llvm::Type *SymtabPtrTy;
+ llvm::Type *SymtabPtrTy;
/// ModuleTy - LLVM type for struct objc_module.
- const llvm::StructType *ModuleTy;
+ llvm::StructType *ModuleTy;
/// ProtocolTy - LLVM type for struct objc_protocol.
- const llvm::StructType *ProtocolTy;
+ llvm::StructType *ProtocolTy;
/// ProtocolPtrTy - LLVM type for struct objc_protocol *.
- const llvm::Type *ProtocolPtrTy;
+ llvm::Type *ProtocolPtrTy;
/// ProtocolExtensionTy - LLVM type for struct
/// objc_protocol_extension.
- const llvm::StructType *ProtocolExtensionTy;
+ llvm::StructType *ProtocolExtensionTy;
/// ProtocolExtensionTy - LLVM type for struct
/// objc_protocol_extension *.
- const llvm::Type *ProtocolExtensionPtrTy;
+ llvm::Type *ProtocolExtensionPtrTy;
/// MethodDescriptionTy - LLVM type for struct
/// objc_method_description.
- const llvm::StructType *MethodDescriptionTy;
+ llvm::StructType *MethodDescriptionTy;
/// MethodDescriptionListTy - LLVM type for struct
/// objc_method_description_list.
- const llvm::StructType *MethodDescriptionListTy;
+ llvm::StructType *MethodDescriptionListTy;
/// MethodDescriptionListPtrTy - LLVM type for struct
/// objc_method_description_list *.
- const llvm::Type *MethodDescriptionListPtrTy;
+ llvm::Type *MethodDescriptionListPtrTy;
/// ProtocolListTy - LLVM type for struct objc_property_list.
- const llvm::Type *ProtocolListTy;
+ llvm::StructType *ProtocolListTy;
/// ProtocolListPtrTy - LLVM type for struct objc_property_list*.
- const llvm::Type *ProtocolListPtrTy;
+ llvm::Type *ProtocolListPtrTy;
/// CategoryTy - LLVM type for struct objc_category.
- const llvm::StructType *CategoryTy;
+ llvm::StructType *CategoryTy;
/// ClassTy - LLVM type for struct objc_class.
- const llvm::StructType *ClassTy;
+ llvm::StructType *ClassTy;
/// ClassPtrTy - LLVM type for struct objc_class *.
- const llvm::Type *ClassPtrTy;
+ llvm::Type *ClassPtrTy;
/// ClassExtensionTy - LLVM type for struct objc_class_ext.
- const llvm::StructType *ClassExtensionTy;
+ llvm::StructType *ClassExtensionTy;
/// ClassExtensionPtrTy - LLVM type for struct objc_class_ext *.
- const llvm::Type *ClassExtensionPtrTy;
+ llvm::Type *ClassExtensionPtrTy;
// IvarTy - LLVM type for struct objc_ivar.
- const llvm::StructType *IvarTy;
+ llvm::StructType *IvarTy;
/// IvarListTy - LLVM type for struct objc_ivar_list.
- const llvm::Type *IvarListTy;
+ llvm::Type *IvarListTy;
/// IvarListPtrTy - LLVM type for struct objc_ivar_list *.
- const llvm::Type *IvarListPtrTy;
+ llvm::Type *IvarListPtrTy;
/// MethodListTy - LLVM type for struct objc_method_list.
- const llvm::Type *MethodListTy;
+ llvm::Type *MethodListTy;
/// MethodListPtrTy - LLVM type for struct objc_method_list *.
- const llvm::Type *MethodListPtrTy;
+ llvm::Type *MethodListPtrTy;
/// ExceptionDataTy - LLVM type for struct _objc_exception_data.
- const llvm::Type *ExceptionDataTy;
-
+ llvm::Type *ExceptionDataTy;
+
/// ExceptionTryEnterFn - LLVM objc_exception_try_enter function.
llvm::Constant *getExceptionTryEnterFn() {
- const llvm::Type *params[] = { ExceptionDataTy->getPointerTo() };
+ llvm::Type *params[] = { ExceptionDataTy->getPointerTo() };
return CGM.CreateRuntimeFunction(
llvm::FunctionType::get(CGM.VoidTy, params, false),
"objc_exception_try_enter");
@@ -460,7 +463,7 @@ public:
/// ExceptionTryExitFn - LLVM objc_exception_try_exit function.
llvm::Constant *getExceptionTryExitFn() {
- const llvm::Type *params[] = { ExceptionDataTy->getPointerTo() };
+ llvm::Type *params[] = { ExceptionDataTy->getPointerTo() };
return CGM.CreateRuntimeFunction(
llvm::FunctionType::get(CGM.VoidTy, params, false),
"objc_exception_try_exit");
@@ -468,7 +471,7 @@ public:
/// ExceptionExtractFn - LLVM objc_exception_extract function.
llvm::Constant *getExceptionExtractFn() {
- const llvm::Type *params[] = { ExceptionDataTy->getPointerTo() };
+ llvm::Type *params[] = { ExceptionDataTy->getPointerTo() };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
params, false),
"objc_exception_extract");
@@ -476,7 +479,7 @@ public:
/// ExceptionMatchFn - LLVM objc_exception_match function.
llvm::Constant *getExceptionMatchFn() {
- const llvm::Type *params[] = { ClassPtrTy, ObjectPtrTy };
+ llvm::Type *params[] = { ClassPtrTy, ObjectPtrTy };
return CGM.CreateRuntimeFunction(
llvm::FunctionType::get(CGM.Int32Ty, params, false),
"objc_exception_match");
@@ -486,7 +489,7 @@ public:
/// SetJmpFn - LLVM _setjmp function.
llvm::Constant *getSetJmpFn() {
// This is specifically the prototype for x86.
- const llvm::Type *params[] = { CGM.Int32Ty->getPointerTo() };
+ llvm::Type *params[] = { CGM.Int32Ty->getPointerTo() };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.Int32Ty,
params, false),
"_setjmp");
@@ -503,46 +506,46 @@ class ObjCNonFragileABITypesHelper : public ObjCCommonTypesHelper {
public:
// MethodListnfABITy - LLVM for struct _method_list_t
- const llvm::StructType *MethodListnfABITy;
+ llvm::StructType *MethodListnfABITy;
// MethodListnfABIPtrTy - LLVM for struct _method_list_t*
- const llvm::Type *MethodListnfABIPtrTy;
+ llvm::Type *MethodListnfABIPtrTy;
// ProtocolnfABITy = LLVM for struct _protocol_t
- const llvm::StructType *ProtocolnfABITy;
+ llvm::StructType *ProtocolnfABITy;
// ProtocolnfABIPtrTy = LLVM for struct _protocol_t*
- const llvm::Type *ProtocolnfABIPtrTy;
+ llvm::Type *ProtocolnfABIPtrTy;
// ProtocolListnfABITy - LLVM for struct _objc_protocol_list
- const llvm::StructType *ProtocolListnfABITy;
+ llvm::StructType *ProtocolListnfABITy;
// ProtocolListnfABIPtrTy - LLVM for struct _objc_protocol_list*
- const llvm::Type *ProtocolListnfABIPtrTy;
+ llvm::Type *ProtocolListnfABIPtrTy;
// ClassnfABITy - LLVM for struct _class_t
- const llvm::StructType *ClassnfABITy;
+ llvm::StructType *ClassnfABITy;
// ClassnfABIPtrTy - LLVM for struct _class_t*
- const llvm::Type *ClassnfABIPtrTy;
+ llvm::Type *ClassnfABIPtrTy;
// IvarnfABITy - LLVM for struct _ivar_t
- const llvm::StructType *IvarnfABITy;
+ llvm::StructType *IvarnfABITy;
// IvarListnfABITy - LLVM for struct _ivar_list_t
- const llvm::StructType *IvarListnfABITy;
+ llvm::StructType *IvarListnfABITy;
// IvarListnfABIPtrTy = LLVM for struct _ivar_list_t*
- const llvm::Type *IvarListnfABIPtrTy;
+ llvm::Type *IvarListnfABIPtrTy;
// ClassRonfABITy - LLVM for struct _class_ro_t
- const llvm::StructType *ClassRonfABITy;
+ llvm::StructType *ClassRonfABITy;
// ImpnfABITy - LLVM for id (*)(id, SEL, ...)
- const llvm::Type *ImpnfABITy;
+ llvm::Type *ImpnfABITy;
// CategorynfABITy - LLVM for struct _category_t
- const llvm::StructType *CategorynfABITy;
+ llvm::StructType *CategorynfABITy;
// New types for nonfragile abi messaging.
@@ -551,31 +554,31 @@ public:
// IMP messenger;
// SEL name;
// };
- const llvm::StructType *MessageRefTy;
+ llvm::StructType *MessageRefTy;
// MessageRefCTy - clang type for struct _message_ref_t
QualType MessageRefCTy;
// MessageRefPtrTy - LLVM for struct _message_ref_t*
- const llvm::Type *MessageRefPtrTy;
+ llvm::Type *MessageRefPtrTy;
// MessageRefCPtrTy - clang type for struct _message_ref_t*
QualType MessageRefCPtrTy;
// MessengerTy - Type of the messenger (shown as IMP above)
- const llvm::FunctionType *MessengerTy;
+ llvm::FunctionType *MessengerTy;
// SuperMessageRefTy - LLVM for:
// struct _super_message_ref_t {
// SUPER_IMP messenger;
// SEL name;
// };
- const llvm::StructType *SuperMessageRefTy;
+ llvm::StructType *SuperMessageRefTy;
// SuperMessageRefPtrTy - LLVM for struct _super_message_ref_t*
- const llvm::Type *SuperMessageRefPtrTy;
+ llvm::Type *SuperMessageRefPtrTy;
llvm::Constant *getMessageSendFixupFn() {
// id objc_msgSend_fixup(id, struct message_ref_t*, ...)
- const llvm::Type *params[] = { ObjectPtrTy, MessageRefPtrTy };
+ llvm::Type *params[] = { ObjectPtrTy, MessageRefPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
params, true),
"objc_msgSend_fixup");
@@ -583,7 +586,7 @@ public:
llvm::Constant *getMessageSendFpretFixupFn() {
// id objc_msgSend_fpret_fixup(id, struct message_ref_t*, ...)
- const llvm::Type *params[] = { ObjectPtrTy, MessageRefPtrTy };
+ llvm::Type *params[] = { ObjectPtrTy, MessageRefPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
params, true),
"objc_msgSend_fpret_fixup");
@@ -591,7 +594,7 @@ public:
llvm::Constant *getMessageSendStretFixupFn() {
// id objc_msgSend_stret_fixup(id, struct message_ref_t*, ...)
- const llvm::Type *params[] = { ObjectPtrTy, MessageRefPtrTy };
+ llvm::Type *params[] = { ObjectPtrTy, MessageRefPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
params, true),
"objc_msgSend_stret_fixup");
@@ -600,7 +603,7 @@ public:
llvm::Constant *getMessageSendSuper2FixupFn() {
// id objc_msgSendSuper2_fixup (struct objc_super *,
// struct _super_message_ref_t*, ...)
- const llvm::Type *params[] = { SuperPtrTy, SuperMessageRefPtrTy };
+ llvm::Type *params[] = { SuperPtrTy, SuperMessageRefPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
params, true),
"objc_msgSendSuper2_fixup");
@@ -609,7 +612,7 @@ public:
llvm::Constant *getMessageSendSuper2StretFixupFn() {
// id objc_msgSendSuper2_stret_fixup(struct objc_super *,
// struct _super_message_ref_t*, ...)
- const llvm::Type *params[] = { SuperPtrTy, SuperMessageRefPtrTy };
+ llvm::Type *params[] = { SuperPtrTy, SuperMessageRefPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
params, true),
"objc_msgSendSuper2_stret_fixup");
@@ -622,15 +625,15 @@ public:
}
llvm::Constant *getObjCBeginCatchFn() {
- const llvm::Type *params[] = { Int8PtrTy };
+ llvm::Type *params[] = { Int8PtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(Int8PtrTy,
params, false),
"objc_begin_catch");
}
- const llvm::StructType *EHTypeTy;
- const llvm::Type *EHTypePtrTy;
-
+ llvm::StructType *EHTypeTy;
+ llvm::Type *EHTypePtrTy;
+
ObjCNonFragileABITypesHelper(CodeGen::CodeGenModule &cgm);
~ObjCNonFragileABITypesHelper(){}
};
@@ -887,6 +890,11 @@ private:
llvm::Value *EmitClassRef(CGBuilderTy &Builder,
const ObjCInterfaceDecl *ID);
+ llvm::Value *EmitClassRefFromId(CGBuilderTy &Builder,
+ IdentifierInfo *II);
+
+ llvm::Value *EmitNSAutoreleasePoolClassRef(CGBuilderTy &Builder);
+
/// EmitSuperClassRef - Emits reference to class's main metadata class.
llvm::Value *EmitSuperClassRef(const ObjCInterfaceDecl *ID);
@@ -1158,6 +1166,11 @@ private:
/// for the given class reference.
llvm::Value *EmitClassRef(CGBuilderTy &Builder,
const ObjCInterfaceDecl *ID);
+
+ llvm::Value *EmitClassRefFromId(CGBuilderTy &Builder,
+ IdentifierInfo *II);
+
+ llvm::Value *EmitNSAutoreleasePoolClassRef(CGBuilderTy &Builder);
/// EmitSuperClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy,
/// for the given super class reference.
@@ -1402,6 +1415,19 @@ llvm::Value *CGObjCMac::GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl
}
llvm::Constant *CGObjCMac::GetEHType(QualType T) {
+ if (T->isObjCIdType() ||
+ T->isObjCQualifiedIdType()) {
+ return CGM.GetAddrOfRTTIDescriptor(
+ CGM.getContext().ObjCIdRedefinitionType, /*ForEH=*/true);
+ }
+ if (T->isObjCClassType() ||
+ T->isObjCQualifiedClassType()) {
+ return CGM.GetAddrOfRTTIDescriptor(
+ CGM.getContext().ObjCClassRedefinitionType, /*ForEH=*/true);
+ }
+ if (T->isObjCObjectPointerType())
+ return CGM.GetAddrOfRTTIDescriptor(T, /*ForEH=*/true);
+
llvm_unreachable("asking for catch type for ObjC type in fragile runtime");
return 0;
}
@@ -1526,7 +1552,7 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
Arg0 = CGF.Builder.CreateBitCast(Arg0, ObjCTypes.ObjectPtrTy, "tmp");
ActualArgs.add(RValue::get(Arg0), Arg0Ty);
ActualArgs.add(RValue::get(Sel), CGF.getContext().getObjCSelType());
- ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end());
+ ActualArgs.addFrom(CallArgs);
CodeGenTypes &Types = CGM.getTypes();
const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs,
@@ -1562,7 +1588,7 @@ static Qualifiers::GC GetGCAttrTypeForType(ASTContext &Ctx, QualType FQT) {
if (FQT.isObjCGCStrong())
return Qualifiers::Strong;
- if (FQT.isObjCGCWeak())
+ if (FQT.isObjCGCWeak() || FQT.getObjCLifetime() == Qualifiers::OCL_Weak)
return Qualifiers::Weak;
if (FQT->isObjCObjectPointerType() || FQT->isBlockPointerType())
@@ -1579,7 +1605,8 @@ llvm::Constant *CGObjCCommonMac::BuildGCBlockLayout(CodeGenModule &CGM,
llvm::Constant *nullPtr =
llvm::Constant::getNullValue(llvm::Type::getInt8PtrTy(VMContext));
- if (CGM.getLangOptions().getGCMode() == LangOptions::NonGC)
+ if (CGM.getLangOptions().getGCMode() == LangOptions::NonGC &&
+ !CGM.getLangOptions().ObjCAutoRefCount)
return nullPtr;
bool hasUnion = false;
@@ -1866,7 +1893,7 @@ CGObjCMac::EmitProtocolList(llvm::Twine Name,
// This list is null terminated.
ProtocolRefs.push_back(llvm::Constant::getNullValue(ObjCTypes.ProtocolPtrTy));
- std::vector<llvm::Constant*> Values(3);
+ llvm::Constant *Values[3];
// This field is only used by the runtime.
Values[0] = llvm::Constant::getNullValue(ObjCTypes.ProtocolListPtrTy);
Values[1] = llvm::ConstantInt::get(ObjCTypes.LongTy,
@@ -1876,7 +1903,7 @@ CGObjCMac::EmitProtocolList(llvm::Twine Name,
ProtocolRefs.size()),
ProtocolRefs);
- llvm::Constant *Init = llvm::ConstantStruct::get(VMContext, Values, false);
+ llvm::Constant *Init = llvm::ConstantStruct::getAnon(Values);
llvm::GlobalVariable *GV =
CreateMetadataVar(Name, Init, "__OBJC,__cat_cls_meth,regular,no_dead_strip",
4, false);
@@ -1950,13 +1977,13 @@ llvm::Constant *CGObjCCommonMac::EmitPropertyList(llvm::Twine Name,
unsigned PropertySize =
CGM.getTargetData().getTypeAllocSize(ObjCTypes.PropertyTy);
- std::vector<llvm::Constant*> Values(3);
+ llvm::Constant *Values[3];
Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, PropertySize);
Values[1] = llvm::ConstantInt::get(ObjCTypes.IntTy, Properties.size());
llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.PropertyTy,
Properties.size());
Values[2] = llvm::ConstantArray::get(AT, Properties);
- llvm::Constant *Init = llvm::ConstantStruct::get(VMContext, Values, false);
+ llvm::Constant *Init = llvm::ConstantStruct::getAnon(Values);
llvm::GlobalVariable *GV =
CreateMetadataVar(Name, Init,
@@ -1994,12 +2021,12 @@ llvm::Constant *CGObjCMac::EmitMethodDescList(llvm::Twine Name,
if (Methods.empty())
return llvm::Constant::getNullValue(ObjCTypes.MethodDescriptionListPtrTy);
- std::vector<llvm::Constant*> Values(2);
+ llvm::Constant *Values[2];
Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Methods.size());
llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.MethodDescriptionTy,
Methods.size());
Values[1] = llvm::ConstantArray::get(AT, Methods);
- llvm::Constant *Init = llvm::ConstantStruct::get(VMContext, Values, false);
+ llvm::Constant *Init = llvm::ConstantStruct::getAnon(Values);
llvm::GlobalVariable *GV = CreateMetadataVar(Name, Init, Section, 4, true);
return llvm::ConstantExpr::getBitCast(GV,
@@ -2044,7 +2071,7 @@ void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
ClassMethods.push_back(GetMethodConstant(*i));
}
- std::vector<llvm::Constant*> Values(7);
+ llvm::Constant *Values[7];
Values[0] = GetClassName(OCD->getIdentifier());
Values[1] = GetClassName(Interface->getIdentifier());
LazySymbols.insert(Interface->getIdentifier());
@@ -2129,7 +2156,7 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
Interface->all_referenced_protocol_begin(),
Interface->all_referenced_protocol_end());
unsigned Flags = eClassFlags_Factory;
- if (ID->getNumIvarInitializers())
+ if (ID->hasCXXStructors())
Flags |= eClassFlags_HasCXXStructors;
unsigned Size =
CGM.getContext().getASTObjCImplementationLayout(ID).getSize().getQuantity();
@@ -2166,7 +2193,7 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
}
}
- std::vector<llvm::Constant*> Values(12);
+ llvm::Constant *Values[12];
Values[ 0] = EmitMetaClass(ID, Protocols, ClassMethods);
if (ObjCInterfaceDecl *Super = Interface->getSuperClass()) {
// Record a reference to the super class.
@@ -2225,7 +2252,7 @@ llvm::Constant *CGObjCMac::EmitMetaClass(const ObjCImplementationDecl *ID,
if (ID->getClassInterface()->getVisibility() == HiddenVisibility)
Flags |= eClassFlags_Hidden;
- std::vector<llvm::Constant*> Values(12);
+ llvm::Constant *Values[12];
// The isa for the metaclass is the root of the hierarchy.
const ObjCInterfaceDecl *Root = ID->getClassInterface();
while (const ObjCInterfaceDecl *Super = Root->getSuperClass())
@@ -2339,7 +2366,7 @@ CGObjCMac::EmitClassExtension(const ObjCImplementationDecl *ID) {
uint64_t Size =
CGM.getTargetData().getTypeAllocSize(ObjCTypes.ClassExtensionTy);
- std::vector<llvm::Constant*> Values(3);
+ llvm::Constant *Values[3];
Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size);
Values[1] = BuildIvarLayout(ID, false);
Values[2] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + ID->getName(),
@@ -2383,11 +2410,8 @@ llvm::Constant *CGObjCMac::EmitIvarList(const ObjCImplementationDecl *ID,
ObjCInterfaceDecl *OID =
const_cast<ObjCInterfaceDecl*>(ID->getClassInterface());
- llvm::SmallVector<ObjCIvarDecl*, 16> OIvars;
- CGM.getContext().ShallowCollectObjCIvars(OID, OIvars);
-
- for (unsigned i = 0, e = OIvars.size(); i != e; ++i) {
- ObjCIvarDecl *IVD = OIvars[i];
+ for (ObjCIvarDecl *IVD = OID->all_declared_ivar_begin();
+ IVD; IVD = IVD->getNextIvar()) {
// Ignore unnamed bit-fields.
if (!IVD->getDeclName())
continue;
@@ -2402,12 +2426,12 @@ llvm::Constant *CGObjCMac::EmitIvarList(const ObjCImplementationDecl *ID,
if (Ivars.empty())
return llvm::Constant::getNullValue(ObjCTypes.IvarListPtrTy);
- std::vector<llvm::Constant*> Values(2);
+ llvm::Constant *Values[2];
Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Ivars.size());
llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.IvarTy,
Ivars.size());
Values[1] = llvm::ConstantArray::get(AT, Ivars);
- llvm::Constant *Init = llvm::ConstantStruct::get(VMContext, Values, false);
+ llvm::Constant *Init = llvm::ConstantStruct::getAnon(Values);
llvm::GlobalVariable *GV;
if (ForClass)
@@ -2459,17 +2483,16 @@ llvm::Constant *CGObjCMac::EmitMethodList(llvm::Twine Name,
if (Methods.empty())
return llvm::Constant::getNullValue(ObjCTypes.MethodListPtrTy);
- std::vector<llvm::Constant*> Values(3);
+ llvm::Constant *Values[3];
Values[0] = llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy);
Values[1] = llvm::ConstantInt::get(ObjCTypes.IntTy, Methods.size());
llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.MethodTy,
Methods.size());
Values[2] = llvm::ConstantArray::get(AT, Methods);
- llvm::Constant *Init = llvm::ConstantStruct::get(VMContext, Values, false);
+ llvm::Constant *Init = llvm::ConstantStruct::getAnon(Values);
llvm::GlobalVariable *GV = CreateMetadataVar(Name, Init, Section, 4, true);
- return llvm::ConstantExpr::getBitCast(GV,
- ObjCTypes.MethodListPtrTy);
+ return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.MethodListPtrTy);
}
llvm::Function *CGObjCCommonMac::GenerateMethod(const ObjCMethodDecl *OMD,
@@ -2558,7 +2581,7 @@ namespace {
: S(*S), SyncArgSlot(SyncArgSlot), CallTryExitVar(CallTryExitVar),
ExceptionData(ExceptionData), ObjCTypes(*ObjCTypes) {}
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
// Check whether we need to call objc_exception_try_exit.
// In optimized code, this branch will always be folded.
llvm::BasicBlock *FinallyCallExit =
@@ -2674,14 +2697,12 @@ FragileHazards::FragileHazards(CodeGenFunction &CGF) : CGF(CGF) {
void FragileHazards::emitWriteHazard() {
if (Locals.empty()) return;
- CGF.Builder.CreateCall(WriteHazard, Locals.begin(), Locals.end())
- ->setDoesNotThrow();
+ CGF.Builder.CreateCall(WriteHazard, Locals)->setDoesNotThrow();
}
void FragileHazards::emitReadHazard(CGBuilderTy &Builder) {
assert(!Locals.empty());
- Builder.CreateCall(ReadHazard, Locals.begin(), Locals.end())
- ->setDoesNotThrow();
+ Builder.CreateCall(ReadHazard, Locals)->setDoesNotThrow();
}
/// Emit read hazards in all the protected blocks, i.e. all the blocks
@@ -2745,7 +2766,7 @@ void FragileHazards::collectLocals() {
}
llvm::FunctionType *FragileHazards::GetAsmFnType() {
- llvm::SmallVector<const llvm::Type *, 16> tys(Locals.size());
+ llvm::SmallVector<llvm::Type *, 16> tys(Locals.size());
for (unsigned i = 0, e = Locals.size(); i != e; ++i)
tys[i] = Locals[i]->getType();
return llvm::FunctionType::get(CGF.VoidTy, tys, false);
@@ -3389,7 +3410,7 @@ void CGObjCCommonMac::EmitImageInfo() {
Section = "__DATA, __objc_imageinfo, regular, no_dead_strip";
llvm::GlobalVariable *GV =
CreateMetadataVar("\01L_OBJC_IMAGE_INFO",
- llvm::ConstantArray::get(AT, values, 2),
+ llvm::ConstantArray::get(AT, values),
Section,
0,
true);
@@ -3430,7 +3451,7 @@ llvm::Constant *CGObjCMac::EmitModuleSymbols() {
if (!NumClasses && !NumCategories)
return llvm::Constant::getNullValue(ObjCTypes.SymtabPtrTy);
- std::vector<llvm::Constant*> Values(5);
+ llvm::Constant *Values[5];
Values[0] = llvm::ConstantInt::get(ObjCTypes.LongTy, 0);
Values[1] = llvm::Constant::getNullValue(ObjCTypes.SelectorPtrTy);
Values[2] = llvm::ConstantInt::get(ObjCTypes.ShortTy, NumClasses);
@@ -3452,7 +3473,7 @@ llvm::Constant *CGObjCMac::EmitModuleSymbols() {
NumClasses + NumCategories),
Symbols);
- llvm::Constant *Init = llvm::ConstantStruct::get(VMContext, Values, false);
+ llvm::Constant *Init = llvm::ConstantStruct::getAnon(Values);
llvm::GlobalVariable *GV =
CreateMetadataVar("\01L_OBJC_SYMBOLS", Init,
@@ -3461,25 +3482,35 @@ llvm::Constant *CGObjCMac::EmitModuleSymbols() {
return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.SymtabPtrTy);
}
-llvm::Value *CGObjCMac::EmitClassRef(CGBuilderTy &Builder,
- const ObjCInterfaceDecl *ID) {
- LazySymbols.insert(ID->getIdentifier());
-
- llvm::GlobalVariable *&Entry = ClassReferences[ID->getIdentifier()];
-
+llvm::Value *CGObjCMac::EmitClassRefFromId(CGBuilderTy &Builder,
+ IdentifierInfo *II) {
+ LazySymbols.insert(II);
+
+ llvm::GlobalVariable *&Entry = ClassReferences[II];
+
if (!Entry) {
llvm::Constant *Casted =
- llvm::ConstantExpr::getBitCast(GetClassName(ID->getIdentifier()),
- ObjCTypes.ClassPtrTy);
+ llvm::ConstantExpr::getBitCast(GetClassName(II),
+ ObjCTypes.ClassPtrTy);
Entry =
- CreateMetadataVar("\01L_OBJC_CLASS_REFERENCES_", Casted,
- "__OBJC,__cls_refs,literal_pointers,no_dead_strip",
- 4, true);
+ CreateMetadataVar("\01L_OBJC_CLASS_REFERENCES_", Casted,
+ "__OBJC,__cls_refs,literal_pointers,no_dead_strip",
+ 4, true);
}
-
+
return Builder.CreateLoad(Entry, "tmp");
}
+llvm::Value *CGObjCMac::EmitClassRef(CGBuilderTy &Builder,
+ const ObjCInterfaceDecl *ID) {
+ return EmitClassRefFromId(Builder, ID->getIdentifier());
+}
+
+llvm::Value *CGObjCMac::EmitNSAutoreleasePoolClassRef(CGBuilderTy &Builder) {
+ IdentifierInfo *II = &CGM.getContext().Idents.get("NSAutoreleasePool");
+ return EmitClassRefFromId(Builder, II);
+}
+
llvm::Value *CGObjCMac::EmitSelector(CGBuilderTy &Builder, Selector Sel,
bool lvalue) {
llvm::GlobalVariable *&Entry = SelectorReferences[Sel];
@@ -3567,12 +3598,18 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
uint64_t MaxFieldOffset = 0;
uint64_t MaxSkippedFieldOffset = 0;
uint64_t LastBitfieldOrUnnamedOffset = 0;
+ uint64_t FirstFieldDelta = 0;
if (RecFields.empty())
return;
unsigned WordSizeInBits = CGM.getContext().Target.getPointerWidth(0);
unsigned ByteSizeInBits = CGM.getContext().Target.getCharWidth();
-
+ if (!RD && CGM.getLangOptions().ObjCAutoRefCount) {
+ FieldDecl *FirstField = RecFields[0];
+ FirstFieldDelta =
+ ComputeIvarBaseOffset(CGM, OI, cast<ObjCIvarDecl>(FirstField));
+ }
+
for (unsigned i = 0, e = RecFields.size(); i != e; ++i) {
FieldDecl *Field = RecFields[i];
uint64_t FieldOffset;
@@ -3580,9 +3617,10 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
// Note that 'i' here is actually the field index inside RD of Field,
// although this dependency is hidden.
const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
- FieldOffset = RL.getFieldOffset(i) / ByteSizeInBits;
+ FieldOffset = (RL.getFieldOffset(i) / ByteSizeInBits) - FirstFieldDelta;
} else
- FieldOffset = ComputeIvarBaseOffset(CGM, OI, cast<ObjCIvarDecl>(Field));
+ FieldOffset =
+ ComputeIvarBaseOffset(CGM, OI, cast<ObjCIvarDecl>(Field)) - FirstFieldDelta;
// Skip over unnamed or bitfields
if (!Field->getIdentifier() || Field->isBitField()) {
@@ -3861,16 +3899,25 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayout(
bool hasUnion = false;
const llvm::Type *PtrTy = llvm::Type::getInt8PtrTy(VMContext);
- if (CGM.getLangOptions().getGCMode() == LangOptions::NonGC)
+ if (CGM.getLangOptions().getGCMode() == LangOptions::NonGC &&
+ !CGM.getLangOptions().ObjCAutoRefCount)
return llvm::Constant::getNullValue(PtrTy);
- llvm::SmallVector<ObjCIvarDecl*, 32> Ivars;
- const ObjCInterfaceDecl *OI = OMD->getClassInterface();
- CGM.getContext().DeepCollectObjCIvars(OI, true, Ivars);
-
+ ObjCInterfaceDecl *OI =
+ const_cast<ObjCInterfaceDecl*>(OMD->getClassInterface());
llvm::SmallVector<FieldDecl*, 32> RecFields;
- for (unsigned k = 0, e = Ivars.size(); k != e; ++k)
- RecFields.push_back(cast<FieldDecl>(Ivars[k]));
+ if (CGM.getLangOptions().ObjCAutoRefCount) {
+ for (ObjCIvarDecl *IVD = OI->all_declared_ivar_begin();
+ IVD; IVD = IVD->getNextIvar())
+ RecFields.push_back(cast<FieldDecl>(IVD));
+ }
+ else {
+ llvm::SmallVector<ObjCIvarDecl*, 32> Ivars;
+ CGM.getContext().DeepCollectObjCIvars(OI, true, Ivars);
+
+ for (unsigned k = 0, e = Ivars.size(); k != e; ++k)
+ RecFields.push_back(cast<FieldDecl>(Ivars[k]));
+ }
if (RecFields.empty())
return llvm::Constant::getNullValue(PtrTy);
@@ -4113,21 +4160,19 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm)
// char *name;
// char *attributes;
// }
- PropertyTy = llvm::StructType::get(VMContext, Int8PtrTy, Int8PtrTy, NULL);
- CGM.getModule().addTypeName("struct._prop_t",
- PropertyTy);
+ PropertyTy = llvm::StructType::createNamed("struct._prop_t",
+ Int8PtrTy, Int8PtrTy, NULL);
// struct _prop_list_t {
// uint32_t entsize; // sizeof(struct _prop_t)
// uint32_t count_of_properties;
// struct _prop_t prop_list[count_of_properties];
// }
- PropertyListTy = llvm::StructType::get(VMContext, IntTy,
- IntTy,
- llvm::ArrayType::get(PropertyTy, 0),
- NULL);
- CGM.getModule().addTypeName("struct._prop_list_t",
- PropertyListTy);
+ PropertyListTy =
+ llvm::StructType::createNamed("struct._prop_list_t",
+ IntTy, IntTy,
+ llvm::ArrayType::get(PropertyTy, 0),
+ NULL);
// struct _prop_list_t *
PropertyListPtrTy = llvm::PointerType::getUnqual(PropertyListTy);
@@ -4136,16 +4181,14 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm)
// char *method_type;
// char *_imp;
// }
- MethodTy = llvm::StructType::get(VMContext, SelectorPtrTy,
- Int8PtrTy,
- Int8PtrTy,
- NULL);
- CGM.getModule().addTypeName("struct._objc_method", MethodTy);
+ MethodTy = llvm::StructType::createNamed("struct._objc_method",
+ SelectorPtrTy, Int8PtrTy, Int8PtrTy,
+ NULL);
// struct _objc_cache *
- CacheTy = llvm::OpaqueType::get(VMContext);
- CGM.getModule().addTypeName("struct._objc_cache", CacheTy);
+ CacheTy = llvm::StructType::createNamed(VMContext, "struct._objc_cache");
CachePtrTy = llvm::PointerType::getUnqual(CacheTy);
+
}
ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
@@ -4155,22 +4198,18 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// char *types;
// }
MethodDescriptionTy =
- llvm::StructType::get(VMContext, SelectorPtrTy,
- Int8PtrTy,
- NULL);
- CGM.getModule().addTypeName("struct._objc_method_description",
- MethodDescriptionTy);
+ llvm::StructType::createNamed("struct._objc_method_description",
+ SelectorPtrTy, Int8PtrTy, NULL);
// struct _objc_method_description_list {
// int count;
// struct _objc_method_description[1];
// }
MethodDescriptionListTy =
- llvm::StructType::get(VMContext, IntTy,
- llvm::ArrayType::get(MethodDescriptionTy, 0),
- NULL);
- CGM.getModule().addTypeName("struct._objc_method_description_list",
- MethodDescriptionListTy);
+ llvm::StructType::createNamed("struct._objc_method_description_list",
+ IntTy,
+ llvm::ArrayType::get(MethodDescriptionTy, 0),
+ NULL);
// struct _objc_method_description_list *
MethodDescriptionListPtrTy =
@@ -4185,29 +4224,27 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// struct _objc_property_list *instance_properties;
// }
ProtocolExtensionTy =
- llvm::StructType::get(VMContext, IntTy,
- MethodDescriptionListPtrTy,
- MethodDescriptionListPtrTy,
- PropertyListPtrTy,
- NULL);
- CGM.getModule().addTypeName("struct._objc_protocol_extension",
- ProtocolExtensionTy);
+ llvm::StructType::createNamed("struct._objc_protocol_extension",
+ IntTy,
+ MethodDescriptionListPtrTy,
+ MethodDescriptionListPtrTy,
+ PropertyListPtrTy,
+ NULL);
// struct _objc_protocol_extension *
ProtocolExtensionPtrTy = llvm::PointerType::getUnqual(ProtocolExtensionTy);
// Handle recursive construction of Protocol and ProtocolList types
- llvm::PATypeHolder ProtocolTyHolder = llvm::OpaqueType::get(VMContext);
- llvm::PATypeHolder ProtocolListTyHolder = llvm::OpaqueType::get(VMContext);
+ ProtocolTy =
+ llvm::StructType::createNamed(VMContext, "struct._objc_protocol");
- const llvm::Type *T =
- llvm::StructType::get(VMContext,
- llvm::PointerType::getUnqual(ProtocolListTyHolder),
+ ProtocolListTy =
+ llvm::StructType::createNamed(VMContext, "struct._objc_protocol_list");
+ ProtocolListTy->setBody(llvm::PointerType::getUnqual(ProtocolListTy),
LongTy,
- llvm::ArrayType::get(ProtocolTyHolder, 0),
+ llvm::ArrayType::get(ProtocolTy, 0),
NULL);
- cast<llvm::OpaqueType>(ProtocolListTyHolder.get())->refineAbstractTypeTo(T);
// struct _objc_protocol {
// struct _objc_protocol_extension *isa;
@@ -4216,22 +4253,15 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// struct _objc_method_description_list *instance_methods;
// struct _objc_method_description_list *class_methods;
// }
- T = llvm::StructType::get(VMContext, ProtocolExtensionPtrTy,
- Int8PtrTy,
- llvm::PointerType::getUnqual(ProtocolListTyHolder),
- MethodDescriptionListPtrTy,
- MethodDescriptionListPtrTy,
- NULL);
- cast<llvm::OpaqueType>(ProtocolTyHolder.get())->refineAbstractTypeTo(T);
-
- ProtocolListTy = cast<llvm::StructType>(ProtocolListTyHolder.get());
- CGM.getModule().addTypeName("struct._objc_protocol_list",
- ProtocolListTy);
+ ProtocolTy->setBody(ProtocolExtensionPtrTy, Int8PtrTy,
+ llvm::PointerType::getUnqual(ProtocolListTy),
+ MethodDescriptionListPtrTy,
+ MethodDescriptionListPtrTy,
+ NULL);
+
// struct _objc_protocol_list *
ProtocolListPtrTy = llvm::PointerType::getUnqual(ProtocolListTy);
- ProtocolTy = cast<llvm::StructType>(ProtocolTyHolder.get());
- CGM.getModule().addTypeName("struct._objc_protocol", ProtocolTy);
ProtocolPtrTy = llvm::PointerType::getUnqual(ProtocolTy);
// Class description structures
@@ -4241,32 +4271,26 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// char *ivar_type;
// int ivar_offset;
// }
- IvarTy = llvm::StructType::get(VMContext, Int8PtrTy,
- Int8PtrTy,
- IntTy,
- NULL);
- CGM.getModule().addTypeName("struct._objc_ivar", IvarTy);
+ IvarTy = llvm::StructType::createNamed("struct._objc_ivar",
+ Int8PtrTy, Int8PtrTy, IntTy, NULL);
// struct _objc_ivar_list *
- IvarListTy = llvm::OpaqueType::get(VMContext);
- CGM.getModule().addTypeName("struct._objc_ivar_list", IvarListTy);
+ IvarListTy =
+ llvm::StructType::createNamed(VMContext, "struct._objc_ivar_list");
IvarListPtrTy = llvm::PointerType::getUnqual(IvarListTy);
// struct _objc_method_list *
- MethodListTy = llvm::OpaqueType::get(VMContext);
- CGM.getModule().addTypeName("struct._objc_method_list", MethodListTy);
+ MethodListTy =
+ llvm::StructType::createNamed(VMContext, "struct._objc_method_list");
MethodListPtrTy = llvm::PointerType::getUnqual(MethodListTy);
// struct _objc_class_extension *
ClassExtensionTy =
- llvm::StructType::get(VMContext, IntTy,
- Int8PtrTy,
- PropertyListPtrTy,
- NULL);
- CGM.getModule().addTypeName("struct._objc_class_extension", ClassExtensionTy);
+ llvm::StructType::createNamed("struct._objc_class_extension",
+ IntTy, Int8PtrTy, PropertyListPtrTy, NULL);
ClassExtensionPtrTy = llvm::PointerType::getUnqual(ClassExtensionTy);
- llvm::PATypeHolder ClassTyHolder = llvm::OpaqueType::get(VMContext);
+ ClassTy = llvm::StructType::createNamed(VMContext, "struct._objc_class");
// struct _objc_class {
// Class isa;
@@ -4282,24 +4306,20 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// char *ivar_layout;
// struct _objc_class_ext *ext;
// };
- T = llvm::StructType::get(VMContext,
- llvm::PointerType::getUnqual(ClassTyHolder),
- llvm::PointerType::getUnqual(ClassTyHolder),
- Int8PtrTy,
- LongTy,
- LongTy,
- LongTy,
- IvarListPtrTy,
- MethodListPtrTy,
- CachePtrTy,
- ProtocolListPtrTy,
- Int8PtrTy,
- ClassExtensionPtrTy,
- NULL);
- cast<llvm::OpaqueType>(ClassTyHolder.get())->refineAbstractTypeTo(T);
-
- ClassTy = cast<llvm::StructType>(ClassTyHolder.get());
- CGM.getModule().addTypeName("struct._objc_class", ClassTy);
+ ClassTy->setBody(llvm::PointerType::getUnqual(ClassTy),
+ llvm::PointerType::getUnqual(ClassTy),
+ Int8PtrTy,
+ LongTy,
+ LongTy,
+ LongTy,
+ IvarListPtrTy,
+ MethodListPtrTy,
+ CachePtrTy,
+ ProtocolListPtrTy,
+ Int8PtrTy,
+ ClassExtensionPtrTy,
+ NULL);
+
ClassPtrTy = llvm::PointerType::getUnqual(ClassTy);
// struct _objc_category {
@@ -4310,15 +4330,11 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// uint32_t size; // sizeof(struct _objc_category)
// struct _objc_property_list *instance_properties;// category's @property
// }
- CategoryTy = llvm::StructType::get(VMContext, Int8PtrTy,
- Int8PtrTy,
- MethodListPtrTy,
- MethodListPtrTy,
- ProtocolListPtrTy,
- IntTy,
- PropertyListPtrTy,
- NULL);
- CGM.getModule().addTypeName("struct._objc_category", CategoryTy);
+ CategoryTy =
+ llvm::StructType::createNamed("struct._objc_category",
+ Int8PtrTy, Int8PtrTy, MethodListPtrTy,
+ MethodListPtrTy, ProtocolListPtrTy,
+ IntTy, PropertyListPtrTy, NULL);
// Global metadata structures
@@ -4329,13 +4345,10 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// short cat_def_cnt;
// char *defs[cls_def_cnt + cat_def_cnt];
// }
- SymtabTy = llvm::StructType::get(VMContext, LongTy,
- SelectorPtrTy,
- ShortTy,
- ShortTy,
- llvm::ArrayType::get(Int8PtrTy, 0),
- NULL);
- CGM.getModule().addTypeName("struct._objc_symtab", SymtabTy);
+ SymtabTy =
+ llvm::StructType::createNamed("struct._objc_symtab",
+ LongTy, SelectorPtrTy, ShortTy, ShortTy,
+ llvm::ArrayType::get(Int8PtrTy, 0), NULL);
SymtabPtrTy = llvm::PointerType::getUnqual(SymtabTy);
// struct _objc_module {
@@ -4345,12 +4358,8 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// struct _objc_symtab* symtab;
// }
ModuleTy =
- llvm::StructType::get(VMContext, LongTy,
- LongTy,
- Int8PtrTy,
- SymtabPtrTy,
- NULL);
- CGM.getModule().addTypeName("struct._objc_module", ModuleTy);
+ llvm::StructType::createNamed("struct._objc_module",
+ LongTy, LongTy, Int8PtrTy, SymtabPtrTy, NULL);
// FIXME: This is the size of the setjmp buffer and should be target
@@ -4358,16 +4367,14 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
uint64_t SetJmpBufferSize = 18;
// Exceptions
- const llvm::Type *StackPtrTy = llvm::ArrayType::get(
+ llvm::Type *StackPtrTy = llvm::ArrayType::get(
llvm::Type::getInt8PtrTy(VMContext), 4);
ExceptionDataTy =
- llvm::StructType::get(VMContext,
- llvm::ArrayType::get(llvm::Type::getInt32Ty(VMContext),
- SetJmpBufferSize),
- StackPtrTy, NULL);
- CGM.getModule().addTypeName("struct._objc_exception_data",
- ExceptionDataTy);
+ llvm::StructType::createNamed("struct._objc_exception_data",
+ llvm::ArrayType::get(llvm::Type::getInt32Ty(VMContext),
+ SetJmpBufferSize),
+ StackPtrTy, NULL);
}
@@ -4378,12 +4385,11 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// uint32_t method_count;
// struct _objc_method method_list[method_count];
// }
- MethodListnfABITy = llvm::StructType::get(VMContext, IntTy,
- IntTy,
- llvm::ArrayType::get(MethodTy, 0),
- NULL);
- CGM.getModule().addTypeName("struct.__method_list_t",
- MethodListnfABITy);
+ MethodListnfABITy =
+ llvm::StructType::createNamed("struct.__method_list_t",
+ IntTy, IntTy,
+ llvm::ArrayType::get(MethodTy, 0),
+ NULL);
// struct method_list_t *
MethodListnfABIPtrTy = llvm::PointerType::getUnqual(MethodListnfABITy);
@@ -4401,22 +4407,21 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// }
// Holder for struct _protocol_list_t *
- llvm::PATypeHolder ProtocolListTyHolder = llvm::OpaqueType::get(VMContext);
-
- ProtocolnfABITy = llvm::StructType::get(VMContext, ObjectPtrTy,
- Int8PtrTy,
- llvm::PointerType::getUnqual(
- ProtocolListTyHolder),
- MethodListnfABIPtrTy,
- MethodListnfABIPtrTy,
- MethodListnfABIPtrTy,
- MethodListnfABIPtrTy,
- PropertyListPtrTy,
- IntTy,
- IntTy,
- NULL);
- CGM.getModule().addTypeName("struct._protocol_t",
- ProtocolnfABITy);
+ ProtocolListnfABITy =
+ llvm::StructType::createNamed(VMContext, "struct._objc_protocol_list");
+
+ ProtocolnfABITy =
+ llvm::StructType::createNamed("struct._protocol_t",
+ ObjectPtrTy, Int8PtrTy,
+ llvm::PointerType::getUnqual(ProtocolListnfABITy),
+ MethodListnfABIPtrTy,
+ MethodListnfABIPtrTy,
+ MethodListnfABIPtrTy,
+ MethodListnfABIPtrTy,
+ PropertyListPtrTy,
+ IntTy,
+ IntTy,
+ NULL);
// struct _protocol_t*
ProtocolnfABIPtrTy = llvm::PointerType::getUnqual(ProtocolnfABITy);
@@ -4425,14 +4430,9 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// long protocol_count; // Note, this is 32/64 bit
// struct _protocol_t *[protocol_count];
// }
- ProtocolListnfABITy = llvm::StructType::get(VMContext, LongTy,
- llvm::ArrayType::get(
- ProtocolnfABIPtrTy, 0),
- NULL);
- CGM.getModule().addTypeName("struct._objc_protocol_list",
- ProtocolListnfABITy);
- cast<llvm::OpaqueType>(ProtocolListTyHolder.get())->refineAbstractTypeTo(
- ProtocolListnfABITy);
+ ProtocolListnfABITy->setBody(LongTy,
+ llvm::ArrayType::get(ProtocolnfABIPtrTy, 0),
+ NULL);
// struct _objc_protocol_list*
ProtocolListnfABIPtrTy = llvm::PointerType::getUnqual(ProtocolListnfABITy);
@@ -4444,26 +4444,25 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// uint32_t alignment;
// uint32_t size;
// }
- IvarnfABITy = llvm::StructType::get(VMContext,
- llvm::PointerType::getUnqual(LongTy),
- Int8PtrTy,
- Int8PtrTy,
- IntTy,
- IntTy,
- NULL);
- CGM.getModule().addTypeName("struct._ivar_t", IvarnfABITy);
+ IvarnfABITy =
+ llvm::StructType::createNamed("struct._ivar_t",
+ llvm::PointerType::getUnqual(LongTy),
+ Int8PtrTy,
+ Int8PtrTy,
+ IntTy,
+ IntTy,
+ NULL);
// struct _ivar_list_t {
// uint32 entsize; // sizeof(struct _ivar_t)
// uint32 count;
// struct _iver_t list[count];
// }
- IvarListnfABITy = llvm::StructType::get(VMContext, IntTy,
- IntTy,
- llvm::ArrayType::get(
- IvarnfABITy, 0),
- NULL);
- CGM.getModule().addTypeName("struct._ivar_list_t", IvarListnfABITy);
+ IvarListnfABITy =
+ llvm::StructType::createNamed("struct._ivar_list_t",
+ IntTy, IntTy,
+ llvm::ArrayType::get(IvarnfABITy, 0),
+ NULL);
IvarListnfABIPtrTy = llvm::PointerType::getUnqual(IvarListnfABITy);
@@ -4482,22 +4481,21 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// }
// FIXME. Add 'reserved' field in 64bit abi mode!
- ClassRonfABITy = llvm::StructType::get(VMContext, IntTy,
- IntTy,
- IntTy,
- Int8PtrTy,
- Int8PtrTy,
- MethodListnfABIPtrTy,
- ProtocolListnfABIPtrTy,
- IvarListnfABIPtrTy,
- Int8PtrTy,
- PropertyListPtrTy,
- NULL);
- CGM.getModule().addTypeName("struct._class_ro_t",
- ClassRonfABITy);
+ ClassRonfABITy = llvm::StructType::createNamed("struct._class_ro_t",
+ IntTy,
+ IntTy,
+ IntTy,
+ Int8PtrTy,
+ Int8PtrTy,
+ MethodListnfABIPtrTy,
+ ProtocolListnfABIPtrTy,
+ IvarListnfABIPtrTy,
+ Int8PtrTy,
+ PropertyListPtrTy,
+ NULL);
// ImpnfABITy - LLVM for id (*)(id, SEL, ...)
- const llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
+ llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
ImpnfABITy = llvm::FunctionType::get(ObjectPtrTy, params, false)
->getPointerTo();
@@ -4509,19 +4507,13 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// struct class_ro_t *ro;
// }
- llvm::PATypeHolder ClassTyHolder = llvm::OpaqueType::get(VMContext);
- ClassnfABITy =
- llvm::StructType::get(VMContext,
- llvm::PointerType::getUnqual(ClassTyHolder),
- llvm::PointerType::getUnqual(ClassTyHolder),
- CachePtrTy,
- llvm::PointerType::getUnqual(ImpnfABITy),
- llvm::PointerType::getUnqual(ClassRonfABITy),
- NULL);
- CGM.getModule().addTypeName("struct._class_t", ClassnfABITy);
-
- cast<llvm::OpaqueType>(ClassTyHolder.get())->refineAbstractTypeTo(
- ClassnfABITy);
+ ClassnfABITy = llvm::StructType::createNamed(VMContext, "struct._class_t");
+ ClassnfABITy->setBody(llvm::PointerType::getUnqual(ClassnfABITy),
+ llvm::PointerType::getUnqual(ClassnfABITy),
+ CachePtrTy,
+ llvm::PointerType::getUnqual(ImpnfABITy),
+ llvm::PointerType::getUnqual(ClassRonfABITy),
+ NULL);
// LLVM for struct _class_t *
ClassnfABIPtrTy = llvm::PointerType::getUnqual(ClassnfABITy);
@@ -4534,14 +4526,14 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// const struct _protocol_list_t * const protocols;
// const struct _prop_list_t * const properties;
// }
- CategorynfABITy = llvm::StructType::get(VMContext, Int8PtrTy,
- ClassnfABIPtrTy,
- MethodListnfABIPtrTy,
- MethodListnfABIPtrTy,
- ProtocolListnfABIPtrTy,
- PropertyListPtrTy,
- NULL);
- CGM.getModule().addTypeName("struct._category_t", CategorynfABITy);
+ CategorynfABITy = llvm::StructType::createNamed("struct._category_t",
+ Int8PtrTy,
+ ClassnfABIPtrTy,
+ MethodListnfABIPtrTy,
+ MethodListnfABIPtrTy,
+ ProtocolListnfABIPtrTy,
+ PropertyListPtrTy,
+ NULL);
// New types for nonfragile abi messaging.
CodeGen::CodeGenTypes &Types = CGM.getTypes();
@@ -4576,26 +4568,25 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// SUPER_IMP messenger;
// SEL name;
// };
- SuperMessageRefTy = llvm::StructType::get(VMContext, ImpnfABITy,
- SelectorPtrTy,
- NULL);
- CGM.getModule().addTypeName("struct._super_message_ref_t", SuperMessageRefTy);
+ SuperMessageRefTy =
+ llvm::StructType::createNamed("struct._super_message_ref_t",
+ ImpnfABITy, SelectorPtrTy, NULL);
// SuperMessageRefPtrTy - LLVM for struct _super_message_ref_t*
SuperMessageRefPtrTy = llvm::PointerType::getUnqual(SuperMessageRefTy);
-
+
// struct objc_typeinfo {
// const void** vtable; // objc_ehtype_vtable + 2
// const char* name; // c++ typeinfo string
// Class cls;
// };
- EHTypeTy = llvm::StructType::get(VMContext,
- llvm::PointerType::getUnqual(Int8PtrTy),
- Int8PtrTy,
- ClassnfABIPtrTy,
- NULL);
- CGM.getModule().addTypeName("struct._objc_typeinfo", EHTypeTy);
+ EHTypeTy =
+ llvm::StructType::createNamed("struct._objc_typeinfo",
+ llvm::PointerType::getUnqual(Int8PtrTy),
+ Int8PtrTy,
+ ClassnfABIPtrTy,
+ NULL);
EHTypePtrTy = llvm::PointerType::getUnqual(EHTypeTy);
}
@@ -4743,7 +4734,12 @@ enum MetaDataDlags {
CLS_META = 0x1,
CLS_ROOT = 0x2,
OBJC2_CLS_HIDDEN = 0x10,
- CLS_EXCEPTION = 0x20
+ CLS_EXCEPTION = 0x20,
+
+ /// (Obsolete) ARC-specific: this class has a .release_ivars method
+ CLS_HAS_IVAR_RELEASER = 0x40,
+ /// class was compiled with -fobjc-arr
+ CLS_COMPILED_BY_ARC = 0x80 // (1<<7)
};
/// BuildClassRoTInitializer - generate meta-data for:
/// struct _class_ro_t {
@@ -4767,6 +4763,10 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer(
const ObjCImplementationDecl *ID) {
std::string ClassName = ID->getNameAsString();
std::vector<llvm::Constant*> Values(10); // 11 for 64bit targets!
+
+ if (CGM.getLangOptions().ObjCAutoRefCount)
+ flags |= CLS_COMPILED_BY_ARC;
+
Values[ 0] = llvm::ConstantInt::get(ObjCTypes.IntTy, flags);
Values[ 1] = llvm::ConstantInt::get(ObjCTypes.IntTy, InstanceStart);
Values[ 2] = llvm::ConstantInt::get(ObjCTypes.IntTy, InstanceSize);
@@ -4936,7 +4936,7 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
ID->getClassInterface()->getVisibility() == HiddenVisibility;
if (classIsHidden)
flags |= OBJC2_CLS_HIDDEN;
- if (ID->getNumIvarInitializers())
+ if (ID->hasCXXStructors())
flags |= eClassFlags_ABI2_HasCXXStructors;
if (!ID->getClassInterface()->getSuperClass()) {
// class is root
@@ -4972,7 +4972,7 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
flags = CLS;
if (classIsHidden)
flags |= OBJC2_CLS_HIDDEN;
- if (ID->getNumIvarInitializers())
+ if (ID->hasCXXStructors())
flags |= eClassFlags_ABI2_HasCXXStructors;
if (hasObjCExceptionAttribute(CGM.getContext(), ID->getClassInterface()))
@@ -5174,7 +5174,7 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitMethodList(llvm::Twine Name,
if (Methods.empty())
return llvm::Constant::getNullValue(ObjCTypes.MethodListnfABIPtrTy);
- std::vector<llvm::Constant*> Values(3);
+ llvm::Constant *Values[3];
// sizeof(struct _objc_method)
unsigned Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.MethodTy);
Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size);
@@ -5183,19 +5183,15 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitMethodList(llvm::Twine Name,
llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.MethodTy,
Methods.size());
Values[2] = llvm::ConstantArray::get(AT, Methods);
- llvm::Constant *Init = llvm::ConstantStruct::get(VMContext, Values, false);
+ llvm::Constant *Init = llvm::ConstantStruct::getAnon(Values);
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false,
- llvm::GlobalValue::InternalLinkage,
- Init,
- Name);
- GV->setAlignment(
- CGM.getTargetData().getABITypeAlignment(Init->getType()));
+ llvm::GlobalValue::InternalLinkage, Init, Name);
+ GV->setAlignment(CGM.getTargetData().getABITypeAlignment(Init->getType()));
GV->setSection(Section);
CGM.AddUsedGlobal(GV);
- return llvm::ConstantExpr::getBitCast(GV,
- ObjCTypes.MethodListnfABIPtrTy);
+ return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.MethodListnfABIPtrTy);
}
/// ObjCIvarOffsetVariable - Returns the ivar offset variable for
@@ -5262,17 +5258,14 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList(
std::vector<llvm::Constant*> Ivars, Ivar(5);
- const ObjCInterfaceDecl *OID = ID->getClassInterface();
+ ObjCInterfaceDecl *OID =
+ const_cast<ObjCInterfaceDecl*>(ID->getClassInterface());
assert(OID && "CGObjCNonFragileABIMac::EmitIvarList - null interface");
// FIXME. Consolidate this with similar code in GenerateClass.
- // Collect declared and synthesized ivars in a small vector.
- llvm::SmallVector<ObjCIvarDecl*, 16> OIvars;
- CGM.getContext().ShallowCollectObjCIvars(OID, OIvars);
-
- for (unsigned i = 0, e = OIvars.size(); i != e; ++i) {
- ObjCIvarDecl *IVD = OIvars[i];
+ for (ObjCIvarDecl *IVD = OID->all_declared_ivar_begin();
+ IVD; IVD = IVD->getNextIvar()) {
// Ignore unnamed bit-fields.
if (!IVD->getDeclName())
continue;
@@ -5298,14 +5291,15 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList(
// Return null for empty list.
if (Ivars.empty())
return llvm::Constant::getNullValue(ObjCTypes.IvarListnfABIPtrTy);
- std::vector<llvm::Constant*> Values(3);
+
+ llvm::Constant *Values[3];
unsigned Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.IvarnfABITy);
Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size);
Values[1] = llvm::ConstantInt::get(ObjCTypes.IntTy, Ivars.size());
llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.IvarnfABITy,
Ivars.size());
Values[2] = llvm::ConstantArray::get(AT, Ivars);
- llvm::Constant *Init = llvm::ConstantStruct::get(VMContext, Values, false);
+ llvm::Constant *Init = llvm::ConstantStruct::getAnon(Values);
const char *Prefix = "\01l_OBJC_$_INSTANCE_VARIABLES_";
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false,
@@ -5491,7 +5485,7 @@ CGObjCNonFragileABIMac::EmitProtocolList(llvm::Twine Name,
ProtocolRefs.push_back(llvm::Constant::getNullValue(
ObjCTypes.ProtocolnfABIPtrTy));
- std::vector<llvm::Constant*> Values(2);
+ llvm::Constant *Values[2];
Values[0] =
llvm::ConstantInt::get(ObjCTypes.LongTy, ProtocolRefs.size() - 1);
Values[1] =
@@ -5500,11 +5494,10 @@ CGObjCNonFragileABIMac::EmitProtocolList(llvm::Twine Name,
ProtocolRefs.size()),
ProtocolRefs);
- llvm::Constant *Init = llvm::ConstantStruct::get(VMContext, Values, false);
+ llvm::Constant *Init = llvm::ConstantStruct::getAnon(Values);
GV = new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false,
llvm::GlobalValue::InternalLinkage,
- Init,
- Name);
+ Init, Name);
GV->setSection("__DATA, __objc_const");
GV->setAlignment(
CGM.getTargetData().getABITypeAlignment(Init->getType()));
@@ -5654,8 +5647,7 @@ CGObjCNonFragileABIMac::EmitVTableMessageSend(CodeGenFunction &CGF,
if (!messageRef) {
// Build the message ref structure.
llvm::Constant *values[] = { fn, GetMethodVarName(selector) };
- llvm::Constant *init =
- llvm::ConstantStruct::get(VMContext, values, 2, false);
+ llvm::Constant *init = llvm::ConstantStruct::getAnon(values);
messageRef = new llvm::GlobalVariable(CGM.getModule(),
init->getType(),
/*constant*/ false,
@@ -5719,28 +5711,39 @@ CGObjCNonFragileABIMac::GetClassGlobal(const std::string &Name) {
return GV;
}
-llvm::Value *CGObjCNonFragileABIMac::EmitClassRef(CGBuilderTy &Builder,
- const ObjCInterfaceDecl *ID) {
- llvm::GlobalVariable *&Entry = ClassReferences[ID->getIdentifier()];
-
+llvm::Value *CGObjCNonFragileABIMac::EmitClassRefFromId(CGBuilderTy &Builder,
+ IdentifierInfo *II) {
+ llvm::GlobalVariable *&Entry = ClassReferences[II];
+
if (!Entry) {
- std::string ClassName(getClassSymbolPrefix() + ID->getNameAsString());
+ std::string ClassName(getClassSymbolPrefix() + II->getName().str());
llvm::GlobalVariable *ClassGV = GetClassGlobal(ClassName);
Entry =
- new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABIPtrTy,
- false, llvm::GlobalValue::InternalLinkage,
- ClassGV,
- "\01L_OBJC_CLASSLIST_REFERENCES_$_");
+ new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABIPtrTy,
+ false, llvm::GlobalValue::InternalLinkage,
+ ClassGV,
+ "\01L_OBJC_CLASSLIST_REFERENCES_$_");
Entry->setAlignment(
- CGM.getTargetData().getABITypeAlignment(
- ObjCTypes.ClassnfABIPtrTy));
+ CGM.getTargetData().getABITypeAlignment(
+ ObjCTypes.ClassnfABIPtrTy));
Entry->setSection("__DATA, __objc_classrefs, regular, no_dead_strip");
CGM.AddUsedGlobal(Entry);
}
-
+
return Builder.CreateLoad(Entry, "tmp");
}
+llvm::Value *CGObjCNonFragileABIMac::EmitClassRef(CGBuilderTy &Builder,
+ const ObjCInterfaceDecl *ID) {
+ return EmitClassRefFromId(Builder, ID->getIdentifier());
+}
+
+llvm::Value *CGObjCNonFragileABIMac::EmitNSAutoreleasePoolClassRef(
+ CGBuilderTy &Builder) {
+ IdentifierInfo *II = &CGM.getContext().Idents.get("NSAutoreleasePool");
+ return EmitClassRefFromId(Builder, II);
+}
+
llvm::Value *
CGObjCNonFragileABIMac::EmitSuperClassRef(CGBuilderTy &Builder,
const ObjCInterfaceDecl *ID) {
@@ -6043,12 +6046,10 @@ void CGObjCNonFragileABIMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
llvm::Value *Exception = CGF.EmitScalarExpr(ThrowExpr);
Exception = CGF.Builder.CreateBitCast(Exception, ObjCTypes.ObjectPtrTy,
"tmp");
- llvm::Value *Args[] = { Exception };
- CGF.EmitCallOrInvoke(ObjCTypes.getExceptionThrowFn(),
- Args, Args+1)
+ CGF.EmitCallOrInvoke(ObjCTypes.getExceptionThrowFn(), Exception)
.setDoesNotReturn();
} else {
- CGF.EmitCallOrInvoke(ObjCTypes.getExceptionRethrowFn(), 0, 0)
+ CGF.EmitCallOrInvoke(ObjCTypes.getExceptionRethrowFn())
.setDoesNotReturn();
}
diff --git a/lib/CodeGen/CGObjCRuntime.cpp b/lib/CodeGen/CGObjCRuntime.cpp
index 21150f1f848c..09c8d0b28f9c 100644
--- a/lib/CodeGen/CGObjCRuntime.cpp
+++ b/lib/CodeGen/CGObjCRuntime.cpp
@@ -52,14 +52,14 @@ static uint64_t LookupFieldBitOffset(CodeGen::CodeGenModule &CGM,
// implemented. This should be fixed to get the information from the layout
// directly.
unsigned Index = 0;
- llvm::SmallVector<ObjCIvarDecl*, 16> Ivars;
- CGM.getContext().ShallowCollectObjCIvars(Container, Ivars);
- for (unsigned k = 0, e = Ivars.size(); k != e; ++k) {
- if (Ivar == Ivars[k])
+ ObjCInterfaceDecl *IDecl = const_cast<ObjCInterfaceDecl*>(Container);
+
+ for (ObjCIvarDecl *IVD = IDecl->all_declared_ivar_begin();
+ IVD; IVD = IVD->getNextIvar()) {
+ if (Ivar == IVD)
break;
++Index;
}
- assert(Index != Ivars.size() && "Ivar is not inside container!");
assert(Index < RL->getFieldCount() && "Ivar is not inside record layout!");
return RL->getFieldOffset(Index);
@@ -134,7 +134,7 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF,
ContainingTypeSize, ContainingTypeAlign));
return LValue::MakeBitfield(V, *Info,
- IvarTy.getCVRQualifiers() | CVRQualifiers);
+ IvarTy.withCVRQualifiers(CVRQualifiers));
}
namespace {
@@ -151,13 +151,13 @@ namespace {
bool MightThrow;
llvm::Value *Fn;
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
if (!MightThrow) {
CGF.Builder.CreateCall(Fn)->setDoesNotThrow();
return;
}
- CGF.EmitCallOrInvoke(Fn, 0, 0);
+ CGF.EmitCallOrInvoke(Fn);
}
};
}
@@ -175,10 +175,8 @@ void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF,
CodeGenFunction::FinallyInfo FinallyInfo;
if (const ObjCAtFinallyStmt *Finally = S.getFinallyStmt())
- FinallyInfo = CGF.EnterFinallyBlock(Finally->getFinallyBody(),
- beginCatchFn,
- endCatchFn,
- exceptionRethrowFn);
+ FinallyInfo.enter(CGF, Finally->getFinallyBody(),
+ beginCatchFn, endCatchFn, exceptionRethrowFn);
llvm::SmallVector<CatchHandler, 8> Handlers;
@@ -266,9 +264,9 @@ void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF,
// Go back to the try-statement fallthrough.
CGF.Builder.restoreIP(SavedIP);
- // Pop out of the normal cleanup on the finally.
+ // Pop out of the finally.
if (S.getFinallyStmt())
- CGF.ExitFinallyBlock(FinallyInfo);
+ FinallyInfo.exit(CGF);
if (Cont.isValid())
CGF.EmitBlock(Cont.getBlock());
@@ -281,7 +279,7 @@ namespace {
CallSyncExit(llvm::Value *SyncExitFn, llvm::Value *SyncArg)
: SyncExitFn(SyncExitFn), SyncArg(SyncArg) {}
- void Emit(CodeGenFunction &CGF, bool IsForEHCleanup) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
CGF.Builder.CreateCall(SyncExitFn, SyncArg)->setDoesNotThrow();
}
};
diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h
index 866d5d83fe60..7accc70c9623 100644
--- a/lib/CodeGen/CGObjCRuntime.h
+++ b/lib/CodeGen/CGObjCRuntime.h
@@ -205,7 +205,13 @@ public:
/// interface decl.
virtual llvm::Value *GetClass(CGBuilderTy &Builder,
const ObjCInterfaceDecl *OID) = 0;
-
+
+
+ virtual llvm::Value *EmitNSAutoreleasePoolClassRef(CGBuilderTy &Builder) {
+ assert(false &&"autoreleasepool unsupported in this ABI");
+ return 0;
+ }
+
/// EnumerationMutationFunction - Return the function that's called by the
/// compiler when a mutation is detected during foreach iteration.
virtual llvm::Constant *EnumerationMutationFunction() = 0;
diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp
index c73b199e31f7..e564c7070525 100644
--- a/lib/CodeGen/CGRTTI.cpp
+++ b/lib/CodeGen/CGRTTI.cpp
@@ -658,9 +658,7 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) {
break;
}
- llvm::Constant *Init =
- llvm::ConstantStruct::get(VMContext, &Fields[0], Fields.size(),
- /*Packed=*/false);
+ llvm::Constant *Init = llvm::ConstantStruct::getAnon(Fields);
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(CGM.getModule(), Init->getType(),
diff --git a/lib/CodeGen/CGRecordLayout.h b/lib/CodeGen/CGRecordLayout.h
index 6d9fc0589e93..8a450298f70a 100644
--- a/lib/CodeGen/CGRecordLayout.h
+++ b/lib/CodeGen/CGRecordLayout.h
@@ -176,11 +176,11 @@ class CGRecordLayout {
private:
/// The LLVM type corresponding to this record layout; used when
/// laying it out as a complete object.
- llvm::PATypeHolder CompleteObjectType;
+ llvm::StructType *CompleteObjectType;
/// The LLVM type for the non-virtual part of this record layout;
/// used when laying it out as a base subobject.
- llvm::PATypeHolder BaseSubobjectType;
+ llvm::StructType *BaseSubobjectType;
/// Map from (non-bit-field) struct field to the corresponding llvm struct
/// type field no. This info is populated by record builder.
@@ -208,8 +208,8 @@ private:
bool IsZeroInitializableAsBase : 1;
public:
- CGRecordLayout(const llvm::StructType *CompleteObjectType,
- const llvm::StructType *BaseSubobjectType,
+ CGRecordLayout(llvm::StructType *CompleteObjectType,
+ llvm::StructType *BaseSubobjectType,
bool IsZeroInitializable,
bool IsZeroInitializableAsBase)
: CompleteObjectType(CompleteObjectType),
@@ -219,14 +219,14 @@ public:
/// \brief Return the "complete object" LLVM type associated with
/// this record.
- const llvm::StructType *getLLVMType() const {
- return cast<llvm::StructType>(CompleteObjectType.get());
+ llvm::StructType *getLLVMType() const {
+ return CompleteObjectType;
}
/// \brief Return the "base subobject" LLVM type associated with
/// this record.
- const llvm::StructType *getBaseSubobjectLLVMType() const {
- return cast<llvm::StructType>(BaseSubobjectType.get());
+ llvm::StructType *getBaseSubobjectLLVMType() const {
+ return BaseSubobjectType;
}
/// \brief Check whether this struct can be C++ zero-initialized
diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp
index 0d72f854ba3e..2b07bafa0096 100644
--- a/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -18,6 +18,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Expr.h"
#include "clang/AST/RecordLayout.h"
+#include "clang/Frontend/CodeGenOptions.h"
#include "CodeGenTypes.h"
#include "CGCXXABI.h"
#include "llvm/DerivedTypes.h"
@@ -34,7 +35,7 @@ class CGRecordLayoutBuilder {
public:
/// FieldTypes - Holds the LLVM types that the struct is created from.
///
- llvm::SmallVector<const llvm::Type *, 16> FieldTypes;
+ llvm::SmallVector<llvm::Type *, 16> FieldTypes;
/// BaseSubobjectType - Holds the LLVM type for the non-virtual part
/// of the struct. For example, consider:
@@ -51,7 +52,7 @@ public:
///
/// This only gets initialized if the base subobject type is
/// different from the complete-object type.
- const llvm::StructType *BaseSubobjectType;
+ llvm::StructType *BaseSubobjectType;
/// FieldInfo - Holds a field and its corresponding LLVM field number.
llvm::DenseMap<const FieldDecl *, unsigned> Fields;
@@ -108,8 +109,8 @@ private:
/// LayoutUnionField - Will layout a field in an union and return the type
/// that the field will have.
- const llvm::Type *LayoutUnionField(const FieldDecl *Field,
- const ASTRecordLayout &Layout);
+ llvm::Type *LayoutUnionField(const FieldDecl *Field,
+ const ASTRecordLayout &Layout);
/// LayoutUnion - Will layout a union RecordDecl.
void LayoutUnion(const RecordDecl *D);
@@ -150,7 +151,7 @@ private:
void LayoutBitField(const FieldDecl *D, uint64_t FieldOffset);
/// AppendField - Appends a field with the given offset and type.
- void AppendField(CharUnits fieldOffset, const llvm::Type *FieldTy);
+ void AppendField(CharUnits fieldOffset, llvm::Type *FieldTy);
/// AppendPadding - Appends enough padding bytes so that the total
/// struct size is a multiple of the field alignment.
@@ -164,7 +165,7 @@ private:
/// getByteArrayType - Returns a byte array type with the given number of
/// elements.
- const llvm::Type *getByteArrayType(CharUnits NumBytes);
+ llvm::Type *getByteArrayType(CharUnits NumBytes);
/// AppendBytes - Append a given number of bytes to the record.
void AppendBytes(CharUnits numBytes);
@@ -229,7 +230,7 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types,
uint64_t FieldSize,
uint64_t ContainingTypeSizeInBits,
unsigned ContainingTypeAlign) {
- const llvm::Type *Ty = Types.ConvertTypeForMemRecursive(FD->getType());
+ const llvm::Type *Ty = Types.ConvertTypeForMem(FD->getType());
CharUnits TypeSizeInBytes =
CharUnits::fromQuantity(Types.getTargetData().getTypeAllocSize(Ty));
uint64_t TypeSizeInBits = Types.getContext().toBits(TypeSizeInBytes);
@@ -268,6 +269,18 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types,
unsigned AccessedTargetBits = 0; // The number of target bits accessed.
unsigned AccessWidth = TypeSizeInBits; // The current access width to attempt.
+ // If requested, widen the initial bit-field access to be register sized. The
+ // theory is that this is most likely to allow multiple accesses into the same
+ // structure to be coalesced, and that the backend should be smart enough to
+ // narrow the store if no coalescing is ever done.
+ //
+ // The subsequent code will handle align these access to common boundaries and
+ // guaranteeing that we do not access past the end of the structure.
+ if (Types.getCodeGenOpts().UseRegisterSizedBitfieldAccess) {
+ if (AccessWidth < Types.getTarget().getRegisterWidth())
+ AccessWidth = Types.getTarget().getRegisterWidth();
+ }
+
// Round down from the field offset to find the first access position that is
// at an aligned offset of the initial access type.
uint64_t AccessStart = FieldOffset - (FieldOffset % AccessWidth);
@@ -427,7 +440,7 @@ bool CGRecordLayoutBuilder::LayoutField(const FieldDecl *D,
CharUnits fieldOffsetInBytes
= Types.getContext().toCharUnitsFromBits(fieldOffset);
- const llvm::Type *Ty = Types.ConvertTypeForMemRecursive(D->getType());
+ llvm::Type *Ty = Types.ConvertTypeForMem(D->getType());
CharUnits typeAlignment = getTypeAlignment(Ty);
// If the type alignment is larger then the struct alignment, we must use
@@ -475,7 +488,7 @@ bool CGRecordLayoutBuilder::LayoutField(const FieldDecl *D,
return true;
}
-const llvm::Type *
+llvm::Type *
CGRecordLayoutBuilder::LayoutUnionField(const FieldDecl *Field,
const ASTRecordLayout &Layout) {
if (Field->isBitField()) {
@@ -486,7 +499,7 @@ CGRecordLayoutBuilder::LayoutUnionField(const FieldDecl *Field,
if (FieldSize == 0)
return 0;
- const llvm::Type *FieldTy = llvm::Type::getInt8Ty(Types.getLLVMContext());
+ llvm::Type *FieldTy = llvm::Type::getInt8Ty(Types.getLLVMContext());
CharUnits NumBytesToAppend = Types.getContext().toCharUnitsFromBits(
llvm::RoundUpToAlignment(FieldSize,
Types.getContext().Target.getCharAlign()));
@@ -502,7 +515,7 @@ CGRecordLayoutBuilder::LayoutUnionField(const FieldDecl *Field,
// This is a regular union field.
Fields[Field] = 0;
- return Types.ConvertTypeForMemRecursive(Field->getType());
+ return Types.ConvertTypeForMem(Field->getType());
}
void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) {
@@ -510,7 +523,7 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) {
const ASTRecordLayout &layout = Types.getContext().getASTRecordLayout(D);
- const llvm::Type *unionType = 0;
+ llvm::Type *unionType = 0;
CharUnits unionSize = CharUnits::Zero();
CharUnits unionAlign = CharUnits::Zero();
@@ -521,7 +534,7 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) {
fieldEnd = D->field_end(); field != fieldEnd; ++field, ++fieldNo) {
assert(layout.getFieldOffset(fieldNo) == 0 &&
"Union field offset did not start at the beginning of record!");
- const llvm::Type *fieldType = LayoutUnionField(*field, layout);
+ llvm::Type *fieldType = LayoutUnionField(*field, layout);
if (!fieldType)
continue;
@@ -586,10 +599,8 @@ void CGRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *base,
// approximation, which is to use the base subobject type if it
// has the same LLVM storage size as the nvsize.
- const llvm::StructType *subobjectType = baseLayout.getBaseSubobjectLLVMType();
+ llvm::StructType *subobjectType = baseLayout.getBaseSubobjectLLVMType();
AppendField(baseOffset, subobjectType);
-
- Types.addBaseSubobjectTypeName(base, baseLayout);
}
void CGRecordLayoutBuilder::LayoutNonVirtualBase(const CXXRecordDecl *base,
@@ -723,13 +734,14 @@ CGRecordLayoutBuilder::ComputeNonVirtualBaseType(const CXXRecordDecl *RD) {
FieldTypes.push_back(getByteArrayType(NumBytes));
}
- BaseSubobjectType = llvm::StructType::get(Types.getLLVMContext(),
- FieldTypes, Packed);
+
+ BaseSubobjectType = llvm::StructType::createNamed(Types.getLLVMContext(), "",
+ FieldTypes, Packed);
+ Types.addRecordTypeName(RD, BaseSubobjectType, ".base");
- if (needsPadding) {
- // Pull the padding back off.
+ // Pull the padding back off.
+ if (needsPadding)
FieldTypes.pop_back();
- }
return true;
}
@@ -806,7 +818,7 @@ void CGRecordLayoutBuilder::AppendTailPadding(CharUnits RecordSize) {
}
void CGRecordLayoutBuilder::AppendField(CharUnits fieldOffset,
- const llvm::Type *fieldType) {
+ llvm::Type *fieldType) {
CharUnits fieldSize =
CharUnits::fromQuantity(Types.getTargetData().getTypeAllocSize(fieldType));
@@ -852,10 +864,10 @@ bool CGRecordLayoutBuilder::ResizeLastBaseFieldIfNecessary(CharUnits offset) {
return true;
}
-const llvm::Type *CGRecordLayoutBuilder::getByteArrayType(CharUnits numBytes) {
+llvm::Type *CGRecordLayoutBuilder::getByteArrayType(CharUnits numBytes) {
assert(!numBytes.isZero() && "Empty byte arrays aren't allowed.");
- const llvm::Type *Ty = llvm::Type::getInt8Ty(Types.getLLVMContext());
+ llvm::Type *Ty = llvm::Type::getInt8Ty(Types.getLLVMContext());
if (numBytes > CharUnits::One())
Ty = llvm::ArrayType::get(Ty, numBytes.getQuantity());
@@ -911,17 +923,16 @@ void CGRecordLayoutBuilder::CheckZeroInitializable(QualType T) {
}
}
-CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) {
+CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D,
+ llvm::StructType *Ty) {
CGRecordLayoutBuilder Builder(*this);
Builder.Layout(D);
- const llvm::StructType *Ty = llvm::StructType::get(getLLVMContext(),
- Builder.FieldTypes,
- Builder.Packed);
+ Ty->setBody(Builder.FieldTypes, Builder.Packed);
// If we're in C++, compute the base subobject type.
- const llvm::StructType *BaseTy = 0;
+ llvm::StructType *BaseTy = 0;
if (isa<CXXRecordDecl>(D)) {
BaseTy = Builder.BaseSubobjectType;
if (!BaseTy) BaseTy = Ty;
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index a982621be79a..07bddb797265 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -151,6 +151,9 @@ void CodeGenFunction::EmitStmt(const Stmt *S) {
case Stmt::ObjCForCollectionStmtClass:
EmitObjCForCollectionStmt(cast<ObjCForCollectionStmt>(*S));
break;
+ case Stmt::ObjCAutoreleasePoolStmtClass:
+ EmitObjCAutoreleasePoolStmt(cast<ObjCAutoreleasePoolStmt>(*S));
+ break;
case Stmt::CXXTryStmtClass:
EmitCXXTryStmt(cast<CXXTryStmt>(*S));
@@ -764,7 +767,7 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
} else if (RV->getType()->isAnyComplexType()) {
EmitComplexExprIntoAddr(RV, ReturnValue, false);
} else {
- EmitAggExpr(RV, AggValueSlot::forAddr(ReturnValue, false, true));
+ EmitAggExpr(RV, AggValueSlot::forAddr(ReturnValue, Qualifiers(), true));
}
EmitBranchThroughCleanup(ReturnBlock);
@@ -1275,11 +1278,16 @@ AddVariableConstraints(const std::string &Constraint, const Expr &AsmExpr,
return Constraint;
llvm::StringRef Register = Attr->getLabel();
assert(Target.isValidGCCRegisterName(Register));
- // FIXME: We should check which registers are compatible with "r" or "x".
- if (Constraint != "r" && Constraint != "x") {
+ // We're using validateOutputConstraint here because we only care if
+ // this is a register constraint.
+ TargetInfo::ConstraintInfo Info(Constraint, "");
+ if (Target.validateOutputConstraint(Info) &&
+ !Info.allowsRegister()) {
CGM.ErrorUnsupported(&Stmt, "__asm__");
return Constraint;
}
+ // Canonicalize the register here before returning it.
+ Register = Target.getNormalizedGCCRegisterName(Register);
return "{" + Register.str() + "}";
}
@@ -1291,7 +1299,7 @@ CodeGenFunction::EmitAsmInputLValue(const AsmStmt &S,
llvm::Value *Arg;
if (Info.allowsRegister() || !Info.allowsMemory()) {
if (!CodeGenFunction::hasAggregateLLVMType(InputType)) {
- Arg = EmitLoadOfLValue(InputValue, InputType).getScalarVal();
+ Arg = EmitLoadOfLValue(InputValue).getScalarVal();
} else {
const llvm::Type *Ty = ConvertType(InputType);
uint64_t Size = CGM.getTargetData().getTypeSizeInBits(Ty);
@@ -1400,15 +1408,15 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
std::vector<LValue> ResultRegDests;
std::vector<QualType> ResultRegQualTys;
- std::vector<const llvm::Type *> ResultRegTypes;
- std::vector<const llvm::Type *> ResultTruncRegTypes;
- std::vector<const llvm::Type*> ArgTypes;
+ std::vector<llvm::Type *> ResultRegTypes;
+ std::vector<llvm::Type *> ResultTruncRegTypes;
+ std::vector<llvm::Type*> ArgTypes;
std::vector<llvm::Value*> Args;
// Keep track of inout constraints.
std::string InOutConstraints;
std::vector<llvm::Value*> InOutArgs;
- std::vector<const llvm::Type*> InOutArgTypes;
+ std::vector<llvm::Type*> InOutArgTypes;
for (unsigned i = 0, e = S.getNumOutputs(); i != e; i++) {
TargetInfo::ConstraintInfo &Info = OutputConstraintInfos[i];
@@ -1457,7 +1465,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
ResultRegTypes.back() = ConvertType(InputTy);
}
}
- if (const llvm::Type* AdjTy =
+ if (llvm::Type* AdjTy =
getTargetHooks().adjustInlineAsmType(*this, OutputConstraint,
ResultRegTypes.back()))
ResultRegTypes.back() = AdjTy;
@@ -1550,6 +1558,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
for (unsigned i = 0, e = S.getNumClobbers(); i != e; i++) {
llvm::StringRef Clobber = S.getClobber(i)->getString();
+ if (Clobber != "memory" && Clobber != "cc")
Clobber = Target.getNormalizedGCCRegisterName(Clobber);
if (i != 0 || NumConstraints != 0)
@@ -1582,7 +1591,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
llvm::InlineAsm *IA =
llvm::InlineAsm::get(FTy, AsmString, Constraints,
S.isVolatile() || S.getNumOutputs() == 0);
- llvm::CallInst *Result = Builder.CreateCall(IA, Args.begin(), Args.end());
+ llvm::CallInst *Result = Builder.CreateCall(IA, Args);
Result->addAttribute(~0, llvm::Attribute::NoUnwind);
// Slap the source location of the inline asm into a !srcloc metadata on the
@@ -1629,7 +1638,6 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
}
}
- EmitStoreThroughLValue(RValue::get(Tmp), ResultRegDests[i],
- ResultRegQualTys[i]);
+ EmitStoreThroughLValue(RValue::get(Tmp), ResultRegDests[i]);
}
}
diff --git a/lib/CodeGen/CGTemporaries.cpp b/lib/CodeGen/CGTemporaries.cpp
index 3b4c50910bf8..0387daeb654f 100644
--- a/lib/CodeGen/CGTemporaries.cpp
+++ b/lib/CodeGen/CGTemporaries.cpp
@@ -16,9 +16,12 @@ using namespace clang;
using namespace CodeGen;
namespace {
- struct DestroyTemporary {
- static void Emit(CodeGenFunction &CGF, bool forEH,
- const CXXDestructorDecl *dtor, llvm::Value *addr) {
+ struct DestroyTemporary : EHScopeStack::Cleanup {
+ const CXXDestructorDecl *dtor;
+ llvm::Value *addr;
+ DestroyTemporary(const CXXDestructorDecl *dtor, llvm::Value *addr)
+ : dtor(dtor), addr(addr) {}
+ void Emit(CodeGenFunction &CGF, Flags flags) {
CGF.EmitCXXDestructorCall(dtor, Dtor_Complete, /*ForVirtualBase=*/false,
addr);
}
diff --git a/lib/CodeGen/CGVTT.cpp b/lib/CodeGen/CGVTT.cpp
index aefc41e50002..cec02cdfc235 100644
--- a/lib/CodeGen/CGVTT.cpp
+++ b/lib/CodeGen/CGVTT.cpp
@@ -390,8 +390,7 @@ CodeGenVTables::EmitVTTDefinition(llvm::GlobalVariable *VTT,
llvm::ArrayType::get(Int8PtrTy, Builder.getVTTComponents().size());
llvm::Constant *Init =
- llvm::ConstantArray::get(ArrayType, Builder.getVTTComponents().data(),
- Builder.getVTTComponents().size());
+ llvm::ConstantArray::get(ArrayType, Builder.getVTTComponents());
VTT->setInitializer(Init);
diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp
index 9ac5e67ada4d..c161b79fd3a0 100644
--- a/lib/CodeGen/CGVTables.cpp
+++ b/lib/CodeGen/CGVTables.cpp
@@ -2937,7 +2937,8 @@ void CodeGenVTables::MaybeEmitThunkAvailableExternally(GlobalDecl GD,
// We can't emit thunks for member functions with incomplete types.
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
- if (CGM.getTypes().VerifyFuncTypeComplete(MD->getType().getTypePtr()))
+ if (!CGM.getTypes().isFuncTypeConvertible(
+ cast<FunctionType>(MD->getType().getTypePtr())))
return;
EmitThunk(GD, Thunk, /*UseAvailableExternallyLinkage=*/true);
@@ -3165,7 +3166,7 @@ CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD,
}
llvm::ArrayType *ArrayType = llvm::ArrayType::get(Int8PtrTy, NumComponents);
- return llvm::ConstantArray::get(ArrayType, Inits.data(), Inits.size());
+ return llvm::ConstantArray::get(ArrayType, Inits);
}
llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTable(const CXXRecordDecl *RD) {
diff --git a/lib/CodeGen/CGVTables.h b/lib/CodeGen/CGVTables.h
index e830e9a6fbcb..eff6e56c1f80 100644
--- a/lib/CodeGen/CGVTables.h
+++ b/lib/CodeGen/CGVTables.h
@@ -18,7 +18,7 @@
#include "llvm/GlobalVariable.h"
#include "clang/Basic/ABI.h"
#include "clang/AST/CharUnits.h"
-#include "GlobalDecl.h"
+#include "clang/AST/GlobalDecl.h"
namespace clang {
class CXXRecordDecl;
diff --git a/lib/CodeGen/CGValue.h b/lib/CodeGen/CGValue.h
index 7f77d552032a..4d0b8410e451 100644
--- a/lib/CodeGen/CGValue.h
+++ b/lib/CodeGen/CGValue.h
@@ -101,8 +101,6 @@ public:
/// bitfields, this is not a simple LLVM pointer, it may be a pointer plus a
/// bitrange.
class LValue {
- // FIXME: alignment?
-
enum {
Simple, // This is a normal l-value, use getAddress().
VectorElt, // This is a vector element l-value (V[i]), use getVector*
@@ -128,6 +126,8 @@ class LValue {
const ObjCPropertyRefExpr *PropertyRefExpr;
};
+ QualType Type;
+
// 'const' is unused here
Qualifiers Quals;
@@ -156,8 +156,9 @@ class LValue {
llvm::MDNode *TBAAInfo;
private:
- void Initialize(Qualifiers Quals, unsigned Alignment = 0,
+ void Initialize(QualType Type, Qualifiers Quals, unsigned Alignment = 0,
llvm::MDNode *TBAAInfo = 0) {
+ this->Type = Type;
this->Quals = Quals;
this->Alignment = Alignment;
assert(this->Alignment == Alignment && "Alignment exceeds allowed max!");
@@ -182,6 +183,12 @@ public:
return Quals.getCVRQualifiers() & ~Qualifiers::Const;
}
+ QualType getType() const { return Type; }
+
+ Qualifiers::ObjCLifetime getObjCLifetime() const {
+ return Quals.getObjCLifetime();
+ }
+
bool isObjCIvar() const { return Ivar; }
void setObjCIvar(bool Value) { Ivar = Value; }
@@ -203,6 +210,10 @@ public:
bool isObjCStrong() const {
return Quals.getObjCGCAttr() == Qualifiers::Strong;
}
+
+ bool isVolatile() const {
+ return Quals.hasVolatile();
+ }
Expr *getBaseIvarExp() const { return BaseIvarExp; }
void setBaseIvarExp(Expr *V) { BaseIvarExp = V; }
@@ -219,6 +230,10 @@ public:
// simple lvalue
llvm::Value *getAddress() const { assert(isSimple()); return V; }
+ void setAddress(llvm::Value *address) {
+ assert(isSimple());
+ V = address;
+ }
// vector elt lvalue
llvm::Value *getVectorAddr() const { assert(isVectorElt()); return V; }
@@ -251,36 +266,36 @@ public:
return PropertyRefExpr;
}
- static LValue MakeAddr(llvm::Value *V, QualType T, unsigned Alignment,
- ASTContext &Context,
+ static LValue MakeAddr(llvm::Value *address, QualType type,
+ unsigned alignment, ASTContext &Context,
llvm::MDNode *TBAAInfo = 0) {
- Qualifiers Quals = T.getQualifiers();
- Quals.setObjCGCAttr(Context.getObjCGCAttrKind(T));
+ Qualifiers qs = type.getQualifiers();
+ qs.setObjCGCAttr(Context.getObjCGCAttrKind(type));
LValue R;
R.LVType = Simple;
- R.V = V;
- R.Initialize(Quals, Alignment, TBAAInfo);
+ R.V = address;
+ R.Initialize(type, qs, alignment, TBAAInfo);
return R;
}
static LValue MakeVectorElt(llvm::Value *Vec, llvm::Value *Idx,
- unsigned CVR) {
+ QualType type) {
LValue R;
R.LVType = VectorElt;
R.V = Vec;
R.VectorIdx = Idx;
- R.Initialize(Qualifiers::fromCVRMask(CVR));
+ R.Initialize(type, type.getQualifiers());
return R;
}
static LValue MakeExtVectorElt(llvm::Value *Vec, llvm::Constant *Elts,
- unsigned CVR) {
+ QualType type) {
LValue R;
R.LVType = ExtVectorElt;
R.V = Vec;
R.VectorElts = Elts;
- R.Initialize(Qualifiers::fromCVRMask(CVR));
+ R.Initialize(type, type.getQualifiers());
return R;
}
@@ -290,13 +305,14 @@ public:
/// bit-field.
/// \param Info - The information describing how to perform the bit-field
/// access.
- static LValue MakeBitfield(llvm::Value *BaseValue, const CGBitFieldInfo &Info,
- unsigned CVR) {
+ static LValue MakeBitfield(llvm::Value *BaseValue,
+ const CGBitFieldInfo &Info,
+ QualType type) {
LValue R;
R.LVType = BitField;
R.V = BaseValue;
R.BitFieldInfo = &Info;
- R.Initialize(Qualifiers::fromCVRMask(CVR));
+ R.Initialize(type, type.getQualifiers());
return R;
}
@@ -309,7 +325,7 @@ public:
R.LVType = PropertyRef;
R.V = Base;
R.PropertyRefExpr = E;
- R.Initialize(Qualifiers());
+ R.Initialize(QualType(), Qualifiers());
return R;
}
};
@@ -318,9 +334,11 @@ public:
class AggValueSlot {
/// The address.
llvm::Value *Addr;
+
+ // Qualifiers
+ Qualifiers Quals;
// Associated flags.
- bool VolatileFlag : 1;
bool LifetimeFlag : 1;
bool RequiresGCollection : 1;
@@ -335,25 +353,31 @@ public:
static AggValueSlot ignored() {
AggValueSlot AV;
AV.Addr = 0;
- AV.VolatileFlag = AV.LifetimeFlag = AV.RequiresGCollection = AV.IsZeroed =0;
+ AV.Quals = Qualifiers();
+ AV.LifetimeFlag = AV.RequiresGCollection = AV.IsZeroed =0;
return AV;
}
/// forAddr - Make a slot for an aggregate value.
///
/// \param Volatile - true if the slot should be volatile-initialized
+ ///
+ /// \param Qualifiers - The qualifiers that dictate how the slot
+ /// should be initialied. Only 'volatile' and the Objective-C
+ /// lifetime qualifiers matter.
+ ///
/// \param LifetimeExternallyManaged - true if the slot's lifetime
/// is being externally managed; false if a destructor should be
/// registered for any temporaries evaluated into the slot
/// \param RequiresGCollection - true if the slot is located
/// somewhere that ObjC GC calls should be emitted for
- static AggValueSlot forAddr(llvm::Value *Addr, bool Volatile,
+ static AggValueSlot forAddr(llvm::Value *Addr, Qualifiers Quals,
bool LifetimeExternallyManaged,
bool RequiresGCollection = false,
bool IsZeroed = false) {
AggValueSlot AV;
AV.Addr = Addr;
- AV.VolatileFlag = Volatile;
+ AV.Quals = Quals;
AV.LifetimeFlag = LifetimeExternallyManaged;
AV.RequiresGCollection = RequiresGCollection;
AV.IsZeroed = IsZeroed;
@@ -361,9 +385,10 @@ public:
}
static AggValueSlot forLValue(LValue LV, bool LifetimeExternallyManaged,
- bool RequiresGCollection = false) {
- return forAddr(LV.getAddress(), LV.isVolatileQualified(),
- LifetimeExternallyManaged, RequiresGCollection);
+ bool RequiresGCollection = false,
+ bool IsZeroed = false) {
+ return forAddr(LV.getAddress(), LV.getQuals(),
+ LifetimeExternallyManaged, RequiresGCollection, IsZeroed);
}
bool isLifetimeExternallyManaged() const {
@@ -373,8 +398,14 @@ public:
LifetimeFlag = Managed;
}
+ Qualifiers getQualifiers() const { return Quals; }
+
bool isVolatile() const {
- return VolatileFlag;
+ return Quals.hasVolatile();
+ }
+
+ Qualifiers::ObjCLifetime getObjCLifetime() const {
+ return Quals.getObjCLifetime();
}
bool requiresGCollection() const {
diff --git a/lib/CodeGen/CodeGenAction.cpp b/lib/CodeGen/CodeGenAction.cpp
index 62fa1f9843de..263e01e4f18a 100644
--- a/lib/CodeGen/CodeGenAction.cpp
+++ b/lib/CodeGen/CodeGenAction.cpp
@@ -34,6 +34,7 @@ namespace clang {
BackendAction Action;
const CodeGenOptions &CodeGenOpts;
const TargetOptions &TargetOpts;
+ const LangOptions &LangOpts;
llvm::raw_ostream *AsmOutStream;
ASTContext *Context;
@@ -46,13 +47,16 @@ namespace clang {
public:
BackendConsumer(BackendAction action, Diagnostic &_Diags,
const CodeGenOptions &compopts,
- const TargetOptions &targetopts, bool TimePasses,
+ const TargetOptions &targetopts,
+ const LangOptions &langopts,
+ bool TimePasses,
const std::string &infile, llvm::raw_ostream *OS,
LLVMContext &C) :
Diags(_Diags),
Action(action),
CodeGenOpts(compopts),
TargetOpts(targetopts),
+ LangOpts(langopts),
AsmOutStream(OS),
LLVMIRGeneration("LLVM IR Generation Time"),
Gen(CreateLLVMCodeGen(Diags, infile, compopts, C)) {
@@ -126,7 +130,7 @@ namespace clang {
void *OldContext = Ctx.getInlineAsmDiagnosticContext();
Ctx.setInlineAsmDiagnosticHandler(InlineAsmDiagHandler, this);
- EmitBackendOutput(Diags, CodeGenOpts, TargetOpts,
+ EmitBackendOutput(Diags, CodeGenOpts, TargetOpts, LangOpts,
TheModule.get(), Action, AsmOutStream);
Ctx.setInlineAsmDiagnosticHandler(OldHandler, OldContext);
@@ -285,6 +289,7 @@ ASTConsumer *CodeGenAction::CreateASTConsumer(CompilerInstance &CI,
BEConsumer =
new BackendConsumer(BA, CI.getDiagnostics(),
CI.getCodeGenOpts(), CI.getTargetOpts(),
+ CI.getLangOpts(),
CI.getFrontendOpts().ShowTimers, InFile, OS.take(),
*VMContext);
return BEConsumer;
@@ -332,7 +337,8 @@ void CodeGenAction::ExecuteAction() {
}
EmitBackendOutput(CI.getDiagnostics(), CI.getCodeGenOpts(),
- CI.getTargetOpts(), TheModule.get(),
+ CI.getTargetOpts(), CI.getLangOpts(),
+ TheModule.get(),
BA, OS);
return;
}
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index 150cb69b4d1a..702897a7c448 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -31,7 +31,7 @@ using namespace CodeGen;
CodeGenFunction::CodeGenFunction(CodeGenModule &cgm)
: CodeGenTypeCache(cgm), CGM(cgm),
Target(CGM.getContext().Target), Builder(cgm.getModule().getContext()),
- BlockInfo(0), BlockPointer(0),
+ AutoreleaseResult(false), BlockInfo(0), BlockPointer(0),
NormalCleanupDest(0), EHCleanupDest(0), NextCleanupDestIndex(1),
ExceptionSlot(0), EHSelectorSlot(0),
DebugInfo(0), DisableDebugInfo(false), DidCallStackSave(false),
@@ -45,11 +45,11 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm)
}
-const llvm::Type *CodeGenFunction::ConvertTypeForMem(QualType T) {
+llvm::Type *CodeGenFunction::ConvertTypeForMem(QualType T) {
return CGM.getTypes().ConvertTypeForMem(T);
}
-const llvm::Type *CodeGenFunction::ConvertType(QualType T) {
+llvm::Type *CodeGenFunction::ConvertType(QualType T) {
return CGM.getTypes().ConvertType(T);
}
@@ -142,6 +142,13 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
assert(BreakContinueStack.empty() &&
"mismatched push/pop in break/continue stack!");
+ // Pop any cleanups that might have been associated with the
+ // parameters. Do this in whatever block we're currently in; it's
+ // important to do this before we enter the return block or return
+ // edges will be *really* confused.
+ if (EHStack.stable_begin() != PrologueCleanupDepth)
+ PopCleanupBlocks(PrologueCleanupDepth);
+
// Emit function epilog (to return).
EmitReturnBlock();
@@ -206,15 +213,15 @@ bool CodeGenFunction::ShouldInstrumentFunction() {
/// function instrumentation is enabled.
void CodeGenFunction::EmitFunctionInstrumentation(const char *Fn) {
// void __cyg_profile_func_{enter,exit} (void *this_fn, void *call_site);
- const llvm::PointerType *PointerTy = Int8PtrTy;
- const llvm::Type *ProfileFuncArgs[] = { PointerTy, PointerTy };
+ llvm::PointerType *PointerTy = Int8PtrTy;
+ llvm::Type *ProfileFuncArgs[] = { PointerTy, PointerTy };
const llvm::FunctionType *FunctionTy =
llvm::FunctionType::get(llvm::Type::getVoidTy(getLLVMContext()),
ProfileFuncArgs, false);
llvm::Constant *F = CGM.CreateRuntimeFunction(FunctionTy, Fn);
llvm::CallInst *CallSite = Builder.CreateCall(
- CGM.getIntrinsic(llvm::Intrinsic::returnaddress, 0, 0),
+ CGM.getIntrinsic(llvm::Intrinsic::returnaddress),
llvm::ConstantInt::get(Int32Ty, 0),
"callsite");
@@ -311,9 +318,19 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
ReturnValue = CurFn->arg_begin();
} else {
ReturnValue = CreateIRTemp(RetTy, "retval");
+
+ // Tell the epilog emitter to autorelease the result. We do this
+ // now so that various specialized functions can suppress it
+ // during their IR-generation.
+ if (getLangOptions().ObjCAutoRefCount &&
+ !CurFnInfo->isReturnsRetained() &&
+ RetTy->isObjCRetainableType())
+ AutoreleaseResult = true;
}
EmitStartEHSpec(CurCodeDecl);
+
+ PrologueCleanupDepth = EHStack.stable_begin();
EmitFunctionProlog(*CurFnInfo, CurFn, Args);
if (D && isa<CXXMethodDecl>(D) && cast<CXXMethodDecl>(D)->isInstance())
@@ -326,7 +343,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
QualType Ty = (*i)->getType();
if (Ty->isVariablyModifiedType())
- EmitVLASize(Ty);
+ EmitVariablyModifiedType(Ty);
}
}
@@ -692,13 +709,20 @@ CodeGenFunction::EmitNullInitialization(llvm::Value *DestPtr, QualType Ty) {
if (const VariableArrayType *vlaType =
dyn_cast_or_null<VariableArrayType>(
getContext().getAsArrayType(Ty))) {
- SizeVal = GetVLASize(vlaType);
+ QualType eltType;
+ llvm::Value *numElts;
+ llvm::tie(numElts, eltType) = getVLASize(vlaType);
+
+ SizeVal = numElts;
+ CharUnits eltSize = getContext().getTypeSizeInChars(eltType);
+ if (!eltSize.isOne())
+ SizeVal = Builder.CreateNUWMul(SizeVal, CGM.getSize(eltSize));
vla = vlaType;
} else {
return;
}
} else {
- SizeVal = llvm::ConstantInt::get(IntPtrTy, Size.getQuantity());
+ SizeVal = CGM.getSize(Size);
vla = 0;
}
@@ -761,60 +785,198 @@ llvm::BasicBlock *CodeGenFunction::GetIndirectGotoBlock() {
return IndirectBranch->getParent();
}
-llvm::Value *CodeGenFunction::GetVLASize(const VariableArrayType *VAT) {
- llvm::Value *&SizeEntry = VLASizeMap[VAT->getSizeExpr()];
+/// Computes the length of an array in elements, as well as the base
+/// element type and a properly-typed first element pointer.
+llvm::Value *CodeGenFunction::emitArrayLength(const ArrayType *origArrayType,
+ QualType &baseType,
+ llvm::Value *&addr) {
+ const ArrayType *arrayType = origArrayType;
+
+ // If it's a VLA, we have to load the stored size. Note that
+ // this is the size of the VLA in bytes, not its size in elements.
+ llvm::Value *numVLAElements = 0;
+ if (isa<VariableArrayType>(arrayType)) {
+ numVLAElements = getVLASize(cast<VariableArrayType>(arrayType)).first;
+
+ // Walk into all VLAs. This doesn't require changes to addr,
+ // which has type T* where T is the first non-VLA element type.
+ do {
+ QualType elementType = arrayType->getElementType();
+ arrayType = getContext().getAsArrayType(elementType);
+
+ // If we only have VLA components, 'addr' requires no adjustment.
+ if (!arrayType) {
+ baseType = elementType;
+ return numVLAElements;
+ }
+ } while (isa<VariableArrayType>(arrayType));
- assert(SizeEntry && "Did not emit size for type");
- return SizeEntry;
-}
+ // We get out here only if we find a constant array type
+ // inside the VLA.
+ }
-llvm::Value *CodeGenFunction::EmitVLASize(QualType Ty) {
- assert(Ty->isVariablyModifiedType() &&
- "Must pass variably modified type to EmitVLASizes!");
+ // We have some number of constant-length arrays, so addr should
+ // have LLVM type [M x [N x [...]]]*. Build a GEP that walks
+ // down to the first element of addr.
+ llvm::SmallVector<llvm::Value*, 8> gepIndices;
- EnsureInsertPoint();
+ // GEP down to the array type.
+ llvm::ConstantInt *zero = Builder.getInt32(0);
+ gepIndices.push_back(zero);
+
+ // It's more efficient to calculate the count from the LLVM
+ // constant-length arrays than to re-evaluate the array bounds.
+ uint64_t countFromCLAs = 1;
+
+ const llvm::ArrayType *llvmArrayType =
+ cast<llvm::ArrayType>(
+ cast<llvm::PointerType>(addr->getType())->getElementType());
+ while (true) {
+ assert(isa<ConstantArrayType>(arrayType));
+ assert(cast<ConstantArrayType>(arrayType)->getSize().getZExtValue()
+ == llvmArrayType->getNumElements());
+
+ gepIndices.push_back(zero);
+ countFromCLAs *= llvmArrayType->getNumElements();
+
+ llvmArrayType =
+ dyn_cast<llvm::ArrayType>(llvmArrayType->getElementType());
+ if (!llvmArrayType) break;
+
+ arrayType = getContext().getAsArrayType(arrayType->getElementType());
+ assert(arrayType && "LLVM and Clang types are out-of-synch");
+ }
+
+ baseType = arrayType->getElementType();
+
+ // Create the actual GEP.
+ addr = Builder.CreateInBoundsGEP(addr, gepIndices.begin(),
+ gepIndices.end(), "array.begin");
- if (const VariableArrayType *VAT = getContext().getAsVariableArrayType(Ty)) {
- // unknown size indication requires no size computation.
- if (!VAT->getSizeExpr())
- return 0;
- llvm::Value *&SizeEntry = VLASizeMap[VAT->getSizeExpr()];
+ llvm::Value *numElements
+ = llvm::ConstantInt::get(SizeTy, countFromCLAs);
- if (!SizeEntry) {
- const llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
+ // If we had any VLA dimensions, factor them in.
+ if (numVLAElements)
+ numElements = Builder.CreateNUWMul(numVLAElements, numElements);
- // Get the element size;
- QualType ElemTy = VAT->getElementType();
- llvm::Value *ElemSize;
- if (ElemTy->isVariableArrayType())
- ElemSize = EmitVLASize(ElemTy);
- else
- ElemSize = llvm::ConstantInt::get(SizeTy,
- getContext().getTypeSizeInChars(ElemTy).getQuantity());
+ return numElements;
+}
+
+std::pair<llvm::Value*, QualType>
+CodeGenFunction::getVLASize(QualType type) {
+ const VariableArrayType *vla = getContext().getAsVariableArrayType(type);
+ assert(vla && "type was not a variable array type!");
+ return getVLASize(vla);
+}
+
+std::pair<llvm::Value*, QualType>
+CodeGenFunction::getVLASize(const VariableArrayType *type) {
+ // The number of elements so far; always size_t.
+ llvm::Value *numElements = 0;
- llvm::Value *NumElements = EmitScalarExpr(VAT->getSizeExpr());
- NumElements = Builder.CreateIntCast(NumElements, SizeTy, false, "tmp");
+ QualType elementType;
+ do {
+ elementType = type->getElementType();
+ llvm::Value *vlaSize = VLASizeMap[type->getSizeExpr()];
+ assert(vlaSize && "no size for VLA!");
+ assert(vlaSize->getType() == SizeTy);
- SizeEntry = Builder.CreateMul(ElemSize, NumElements);
+ if (!numElements) {
+ numElements = vlaSize;
+ } else {
+ // It's undefined behavior if this wraps around, so mark it that way.
+ numElements = Builder.CreateNUWMul(numElements, vlaSize);
}
+ } while ((type = getContext().getAsVariableArrayType(elementType)));
- return SizeEntry;
- }
+ return std::pair<llvm::Value*,QualType>(numElements, elementType);
+}
- if (const ArrayType *AT = dyn_cast<ArrayType>(Ty)) {
- EmitVLASize(AT->getElementType());
- return 0;
- }
+void CodeGenFunction::EmitVariablyModifiedType(QualType type) {
+ assert(type->isVariablyModifiedType() &&
+ "Must pass variably modified type to EmitVLASizes!");
- if (const ParenType *PT = dyn_cast<ParenType>(Ty)) {
- EmitVLASize(PT->getInnerType());
- return 0;
- }
+ EnsureInsertPoint();
+
+ // We're going to walk down into the type and look for VLA
+ // expressions.
+ type = type.getCanonicalType();
+ do {
+ assert(type->isVariablyModifiedType());
+
+ const Type *ty = type.getTypePtr();
+ switch (ty->getTypeClass()) {
+#define TYPE(Class, Base)
+#define ABSTRACT_TYPE(Class, Base)
+#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
+#define DEPENDENT_TYPE(Class, Base) case Type::Class:
+#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class:
+#include "clang/AST/TypeNodes.def"
+ llvm_unreachable("unexpected dependent or non-canonical type!");
+
+ // These types are never variably-modified.
+ case Type::Builtin:
+ case Type::Complex:
+ case Type::Vector:
+ case Type::ExtVector:
+ case Type::Record:
+ case Type::Enum:
+ case Type::ObjCObject:
+ case Type::ObjCInterface:
+ case Type::ObjCObjectPointer:
+ llvm_unreachable("type class is never variably-modified!");
+
+ case Type::Pointer:
+ type = cast<PointerType>(ty)->getPointeeType();
+ break;
+
+ case Type::BlockPointer:
+ type = cast<BlockPointerType>(ty)->getPointeeType();
+ break;
+
+ case Type::LValueReference:
+ case Type::RValueReference:
+ type = cast<ReferenceType>(ty)->getPointeeType();
+ break;
+
+ case Type::MemberPointer:
+ type = cast<MemberPointerType>(ty)->getPointeeType();
+ break;
+
+ case Type::ConstantArray:
+ case Type::IncompleteArray:
+ // Losing element qualification here is fine.
+ type = cast<ArrayType>(ty)->getElementType();
+ break;
+
+ case Type::VariableArray: {
+ // Losing element qualification here is fine.
+ const VariableArrayType *vat = cast<VariableArrayType>(ty);
+
+ // Unknown size indication requires no size computation.
+ // Otherwise, evaluate and record it.
+ if (const Expr *size = vat->getSizeExpr()) {
+ // It's possible that we might have emitted this already,
+ // e.g. with a typedef and a pointer to it.
+ llvm::Value *&entry = VLASizeMap[size];
+ if (!entry) {
+ // Always zexting here would be wrong if it weren't
+ // undefined behavior to have a negative bound.
+ entry = Builder.CreateIntCast(EmitScalarExpr(size), SizeTy,
+ /*signed*/ false);
+ }
+ }
+ type = vat->getElementType();
+ break;
+ }
- const PointerType *PT = Ty->getAs<PointerType>();
- assert(PT && "unknown VM type!");
- EmitVLASize(PT->getPointeeType());
- return 0;
+ case Type::FunctionProto:
+ case Type::FunctionNoProto:
+ type = cast<FunctionType>(ty)->getResultType();
+ break;
+ }
+ } while (type->isVariablyModifiedType());
}
llvm::Value* CodeGenFunction::EmitVAListRef(const Expr* E) {
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index bb8fd8e24306..f27ed947b8d8 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -18,8 +18,10 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/CharUnits.h"
+#include "clang/Frontend/CodeGenOptions.h"
#include "clang/Basic/ABI.h"
#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/ValueHandle.h"
@@ -63,6 +65,7 @@ namespace clang {
class ObjCAtTryStmt;
class ObjCAtThrowStmt;
class ObjCAtSynchronizedStmt;
+ class ObjCAutoreleasePoolStmt;
namespace CodeGen {
class CodeGenTypes;
@@ -179,15 +182,39 @@ public:
/// Cleanup implementations should generally be declared in an
/// anonymous namespace.
class Cleanup {
+ // Anchor the construction vtable.
+ virtual void anchor();
public:
- // Anchor the construction vtable. We use the destructor because
- // gcc gives an obnoxious warning if there are virtual methods
- // with an accessible non-virtual destructor. Unfortunately,
- // declaring this destructor makes it non-trivial, but there
- // doesn't seem to be any other way around this warning.
- //
- // This destructor will never be called.
- virtual ~Cleanup();
+ /// Generation flags.
+ class Flags {
+ enum {
+ F_IsForEH = 0x1,
+ F_IsNormalCleanupKind = 0x2,
+ F_IsEHCleanupKind = 0x4
+ };
+ unsigned flags;
+
+ public:
+ Flags() : flags(0) {}
+
+ /// isForEH - true if the current emission is for an EH cleanup.
+ bool isForEHCleanup() const { return flags & F_IsForEH; }
+ bool isForNormalCleanup() const { return !isForEHCleanup(); }
+ void setIsForEHCleanup() { flags |= F_IsForEH; }
+
+ bool isNormalCleanupKind() const { return flags & F_IsNormalCleanupKind; }
+ void setIsNormalCleanupKind() { flags |= F_IsNormalCleanupKind; }
+
+ /// isEHCleanupKind - true if the cleanup was pushed as an EH
+ /// cleanup.
+ bool isEHCleanupKind() const { return flags & F_IsEHCleanupKind; }
+ void setIsEHCleanupKind() { flags |= F_IsEHCleanupKind; }
+ };
+
+ // Provide a virtual destructor to suppress a very common warning
+ // that unfortunately cannot be suppressed without this. Cleanups
+ // should not rely on this destructor ever being called.
+ virtual ~Cleanup() {}
/// Emit the cleanup. For normal cleanups, this is run in the
/// same EH context as when the cleanup was pushed, i.e. the
@@ -196,29 +223,7 @@ public:
///
// \param IsForEHCleanup true if this is for an EH cleanup, false
/// if for a normal cleanup.
- virtual void Emit(CodeGenFunction &CGF, bool IsForEHCleanup) = 0;
- };
-
- /// UnconditionalCleanupN stores its N parameters and just passes
- /// them to the real cleanup function.
- template <class T, class A0>
- class UnconditionalCleanup1 : public Cleanup {
- A0 a0;
- public:
- UnconditionalCleanup1(A0 a0) : a0(a0) {}
- void Emit(CodeGenFunction &CGF, bool IsForEHCleanup) {
- T::Emit(CGF, IsForEHCleanup, a0);
- }
- };
-
- template <class T, class A0, class A1>
- class UnconditionalCleanup2 : public Cleanup {
- A0 a0; A1 a1;
- public:
- UnconditionalCleanup2(A0 a0, A1 a1) : a0(a0), a1(a1) {}
- void Emit(CodeGenFunction &CGF, bool IsForEHCleanup) {
- T::Emit(CGF, IsForEHCleanup, a0, a1);
- }
+ virtual void Emit(CodeGenFunction &CGF, Flags flags) = 0;
};
/// ConditionalCleanupN stores the saved form of its N parameters,
@@ -228,9 +233,9 @@ public:
typedef typename DominatingValue<A0>::saved_type A0_saved;
A0_saved a0_saved;
- void Emit(CodeGenFunction &CGF, bool IsForEHCleanup) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
A0 a0 = DominatingValue<A0>::restore(CGF, a0_saved);
- T::Emit(CGF, IsForEHCleanup, a0);
+ T(a0).Emit(CGF, flags);
}
public:
@@ -245,10 +250,10 @@ public:
A0_saved a0_saved;
A1_saved a1_saved;
- void Emit(CodeGenFunction &CGF, bool IsForEHCleanup) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
A0 a0 = DominatingValue<A0>::restore(CGF, a0_saved);
A1 a1 = DominatingValue<A1>::restore(CGF, a1_saved);
- T::Emit(CGF, IsForEHCleanup, a0, a1);
+ T(a0, a1).Emit(CGF, flags);
}
public:
@@ -256,6 +261,51 @@ public:
: a0_saved(a0), a1_saved(a1) {}
};
+ template <class T, class A0, class A1, class A2>
+ class ConditionalCleanup3 : public Cleanup {
+ typedef typename DominatingValue<A0>::saved_type A0_saved;
+ typedef typename DominatingValue<A1>::saved_type A1_saved;
+ typedef typename DominatingValue<A2>::saved_type A2_saved;
+ A0_saved a0_saved;
+ A1_saved a1_saved;
+ A2_saved a2_saved;
+
+ void Emit(CodeGenFunction &CGF, Flags flags) {
+ A0 a0 = DominatingValue<A0>::restore(CGF, a0_saved);
+ A1 a1 = DominatingValue<A1>::restore(CGF, a1_saved);
+ A2 a2 = DominatingValue<A2>::restore(CGF, a2_saved);
+ T(a0, a1, a2).Emit(CGF, flags);
+ }
+
+ public:
+ ConditionalCleanup3(A0_saved a0, A1_saved a1, A2_saved a2)
+ : a0_saved(a0), a1_saved(a1), a2_saved(a2) {}
+ };
+
+ template <class T, class A0, class A1, class A2, class A3>
+ class ConditionalCleanup4 : public Cleanup {
+ typedef typename DominatingValue<A0>::saved_type A0_saved;
+ typedef typename DominatingValue<A1>::saved_type A1_saved;
+ typedef typename DominatingValue<A2>::saved_type A2_saved;
+ typedef typename DominatingValue<A3>::saved_type A3_saved;
+ A0_saved a0_saved;
+ A1_saved a1_saved;
+ A2_saved a2_saved;
+ A3_saved a3_saved;
+
+ void Emit(CodeGenFunction &CGF, Flags flags) {
+ A0 a0 = DominatingValue<A0>::restore(CGF, a0_saved);
+ A1 a1 = DominatingValue<A1>::restore(CGF, a1_saved);
+ A2 a2 = DominatingValue<A2>::restore(CGF, a2_saved);
+ A3 a3 = DominatingValue<A3>::restore(CGF, a3_saved);
+ T(a0, a1, a2, a3).Emit(CGF, flags);
+ }
+
+ public:
+ ConditionalCleanup4(A0_saved a0, A1_saved a1, A2_saved a2, A3_saved a3)
+ : a0_saved(a0), a1_saved(a1), a2_saved(a2), a3_saved(a3) {}
+ };
+
private:
// The implementation for this class is in CGException.h and
// CGException.cpp; the definition is here because it's used as a
@@ -568,6 +618,10 @@ public:
/// CurGD - The GlobalDecl for the current function being compiled.
GlobalDecl CurGD;
+ /// PrologueCleanupDepth - The cleanup depth enclosing all the
+ /// cleanups associated with the parameters.
+ EHScopeStack::stable_iterator PrologueCleanupDepth;
+
/// ReturnBlock - Unified return block.
JumpDest ReturnBlock;
@@ -584,6 +638,9 @@ public:
bool CatchUndefined;
+ /// In ARC, whether we should autorelease the return value.
+ bool AutoreleaseResult;
+
const CodeGen::CGBlockInfo *BlockInfo;
llvm::Value *BlockPointer;
@@ -626,16 +683,28 @@ public:
/// rethrows.
llvm::SmallVector<llvm::Value*, 8> ObjCEHValueStack;
- // A struct holding information about a finally block's IR
- // generation. For now, doesn't actually hold anything.
- struct FinallyInfo {
- };
+ /// A class controlling the emission of a finally block.
+ class FinallyInfo {
+ /// Where the catchall's edge through the cleanup should go.
+ JumpDest RethrowDest;
+
+ /// A function to call to enter the catch.
+ llvm::Constant *BeginCatchFn;
- FinallyInfo EnterFinallyBlock(const Stmt *Stmt,
- llvm::Constant *BeginCatchFn,
- llvm::Constant *EndCatchFn,
- llvm::Constant *RethrowFn);
- void ExitFinallyBlock(FinallyInfo &FinallyInfo);
+ /// An i1 variable indicating whether or not the @finally is
+ /// running for an exception.
+ llvm::AllocaInst *ForEHVar;
+
+ /// An i8* variable into which the exception pointer to rethrow
+ /// has been saved.
+ llvm::AllocaInst *SavedExnVar;
+
+ public:
+ void enter(CodeGenFunction &CGF, const Stmt *Finally,
+ llvm::Constant *beginCatchFn, llvm::Constant *endCatchFn,
+ llvm::Constant *rethrowFn);
+ void exit(CodeGenFunction &CGF);
+ };
/// pushFullExprCleanup - Push a cleanup to be run at the end of the
/// current full-expression. Safe against the possibility that
@@ -644,10 +713,8 @@ public:
void pushFullExprCleanup(CleanupKind kind, A0 a0) {
// If we're not in a conditional branch, or if none of the
// arguments requires saving, then use the unconditional cleanup.
- if (!isInConditionalBranch()) {
- typedef EHScopeStack::UnconditionalCleanup1<T, A0> CleanupType;
- return EHStack.pushCleanup<CleanupType>(kind, a0);
- }
+ if (!isInConditionalBranch())
+ return EHStack.pushCleanup<T>(kind, a0);
typename DominatingValue<A0>::saved_type a0_saved = saveValueInCond(a0);
@@ -663,10 +730,8 @@ public:
void pushFullExprCleanup(CleanupKind kind, A0 a0, A1 a1) {
// If we're not in a conditional branch, or if none of the
// arguments requires saving, then use the unconditional cleanup.
- if (!isInConditionalBranch()) {
- typedef EHScopeStack::UnconditionalCleanup2<T, A0, A1> CleanupType;
- return EHStack.pushCleanup<CleanupType>(kind, a0, a1);
- }
+ if (!isInConditionalBranch())
+ return EHStack.pushCleanup<T>(kind, a0, a1);
typename DominatingValue<A0>::saved_type a0_saved = saveValueInCond(a0);
typename DominatingValue<A1>::saved_type a1_saved = saveValueInCond(a1);
@@ -676,6 +741,48 @@ public:
initFullExprCleanup();
}
+ /// pushFullExprCleanup - Push a cleanup to be run at the end of the
+ /// current full-expression. Safe against the possibility that
+ /// we're currently inside a conditionally-evaluated expression.
+ template <class T, class A0, class A1, class A2>
+ void pushFullExprCleanup(CleanupKind kind, A0 a0, A1 a1, A2 a2) {
+ // If we're not in a conditional branch, or if none of the
+ // arguments requires saving, then use the unconditional cleanup.
+ if (!isInConditionalBranch()) {
+ return EHStack.pushCleanup<T>(kind, a0, a1, a2);
+ }
+
+ typename DominatingValue<A0>::saved_type a0_saved = saveValueInCond(a0);
+ typename DominatingValue<A1>::saved_type a1_saved = saveValueInCond(a1);
+ typename DominatingValue<A2>::saved_type a2_saved = saveValueInCond(a2);
+
+ typedef EHScopeStack::ConditionalCleanup3<T, A0, A1, A2> CleanupType;
+ EHStack.pushCleanup<CleanupType>(kind, a0_saved, a1_saved, a2_saved);
+ initFullExprCleanup();
+ }
+
+ /// pushFullExprCleanup - Push a cleanup to be run at the end of the
+ /// current full-expression. Safe against the possibility that
+ /// we're currently inside a conditionally-evaluated expression.
+ template <class T, class A0, class A1, class A2, class A3>
+ void pushFullExprCleanup(CleanupKind kind, A0 a0, A1 a1, A2 a2, A3 a3) {
+ // If we're not in a conditional branch, or if none of the
+ // arguments requires saving, then use the unconditional cleanup.
+ if (!isInConditionalBranch()) {
+ return EHStack.pushCleanup<T>(kind, a0, a1, a2, a3);
+ }
+
+ typename DominatingValue<A0>::saved_type a0_saved = saveValueInCond(a0);
+ typename DominatingValue<A1>::saved_type a1_saved = saveValueInCond(a1);
+ typename DominatingValue<A2>::saved_type a2_saved = saveValueInCond(a2);
+ typename DominatingValue<A3>::saved_type a3_saved = saveValueInCond(a3);
+
+ typedef EHScopeStack::ConditionalCleanup4<T, A0, A1, A2, A3> CleanupType;
+ EHStack.pushCleanup<CleanupType>(kind, a0_saved, a1_saved,
+ a2_saved, a3_saved);
+ initFullExprCleanup();
+ }
+
/// PushDestructorCleanup - Push a cleanup to call the
/// complete-object destructor of an object of the given type at the
/// given address. Does nothing if T is not a C++ class type with a
@@ -1048,6 +1155,9 @@ public:
void disableDebugInfo() { DisableDebugInfo = true; }
void enableDebugInfo() { DisableDebugInfo = false; }
+ bool shouldUseFusedARCCalls() {
+ return CGM.getCodeGenOpts().OptimizationLevel == 0;
+ }
const LangOptions &getLangOptions() const { return CGM.getLangOptions(); }
@@ -1075,6 +1185,57 @@ public:
llvm::LLVMContext &getLLVMContext() { return CGM.getLLVMContext(); }
//===--------------------------------------------------------------------===//
+ // Cleanups
+ //===--------------------------------------------------------------------===//
+
+ typedef void Destroyer(CodeGenFunction &CGF, llvm::Value *addr, QualType ty);
+
+ void pushIrregularPartialArrayCleanup(llvm::Value *arrayBegin,
+ llvm::Value *arrayEndPointer,
+ QualType elementType,
+ Destroyer &destroyer);
+ void pushRegularPartialArrayCleanup(llvm::Value *arrayBegin,
+ llvm::Value *arrayEnd,
+ QualType elementType,
+ Destroyer &destroyer);
+
+ void pushDestroy(QualType::DestructionKind dtorKind,
+ llvm::Value *addr, QualType type);
+ void pushDestroy(CleanupKind kind, llvm::Value *addr, QualType type,
+ Destroyer &destroyer, bool useEHCleanupForArray);
+ void emitDestroy(llvm::Value *addr, QualType type, Destroyer &destroyer,
+ bool useEHCleanupForArray);
+ llvm::Function *generateDestroyHelper(llvm::Constant *addr,
+ QualType type,
+ Destroyer &destroyer,
+ bool useEHCleanupForArray);
+ void emitArrayDestroy(llvm::Value *begin, llvm::Value *end,
+ QualType type, Destroyer &destroyer,
+ bool checkZeroLength, bool useEHCleanup);
+
+ Destroyer &getDestroyer(QualType::DestructionKind destructionKind);
+
+ /// Determines whether an EH cleanup is required to destroy a type
+ /// with the given destruction kind.
+ bool needsEHCleanup(QualType::DestructionKind kind) {
+ switch (kind) {
+ case QualType::DK_none:
+ return false;
+ case QualType::DK_cxx_destructor:
+ case QualType::DK_objc_weak_lifetime:
+ return getLangOptions().Exceptions;
+ case QualType::DK_objc_strong_lifetime:
+ return getLangOptions().Exceptions &&
+ CGM.getCodeGenOpts().ObjCAutoRefCountExceptions;
+ }
+ llvm_unreachable("bad destruction kind");
+ }
+
+ CleanupKind getCleanupKind(QualType::DestructionKind kind) {
+ return (needsEHCleanup(kind) ? NormalAndEHCleanup : NormalCleanup);
+ }
+
+ //===--------------------------------------------------------------------===//
// Objective-C
//===--------------------------------------------------------------------===//
@@ -1236,9 +1397,9 @@ public:
/// a terminate scope encloses a try.
llvm::BasicBlock *getTerminateHandler();
- const llvm::Type *ConvertTypeForMem(QualType T);
- const llvm::Type *ConvertType(QualType T);
- const llvm::Type *ConvertType(const TypeDecl *T) {
+ llvm::Type *ConvertTypeForMem(QualType T);
+ llvm::Type *ConvertType(QualType T);
+ llvm::Type *ConvertType(const TypeDecl *T) {
return ConvertType(getContext().getTypeDeclType(T));
}
@@ -1345,7 +1506,8 @@ public:
/// CreateAggTemp - Create a temporary memory object for the given
/// aggregate type.
AggValueSlot CreateAggTemp(QualType T, const llvm::Twine &Name = "tmp") {
- return AggValueSlot::forAddr(CreateMemTemp(T, Name), false, false);
+ return AggValueSlot::forAddr(CreateMemTemp(T, Name), T.getQualifiers(),
+ false);
}
/// Emit a cast to void* in the appropriate address space.
@@ -1379,14 +1541,12 @@ public:
/// EmitAnyExprToMem - Emits the code necessary to evaluate an
/// arbitrary expression into the given memory location.
void EmitAnyExprToMem(const Expr *E, llvm::Value *Location,
- bool IsLocationVolatile,
- bool IsInitializer);
+ Qualifiers Quals, bool IsInitializer);
/// EmitExprAsInit - Emits the code necessary to initialize a
/// location in memory with the given initializer.
- void EmitExprAsInit(const Expr *init, const VarDecl *var,
- llvm::Value *loc, CharUnits alignment,
- bool capturedByInit);
+ void EmitExprAsInit(const Expr *init, const ValueDecl *D,
+ LValue lvalue, bool capturedByInit);
/// EmitAggregateCopy - Emit an aggrate copy.
///
@@ -1451,16 +1611,24 @@ public:
// instruction in LLVM instead once it works well enough.
llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty);
- /// EmitVLASize - Generate code for any VLA size expressions that might occur
- /// in a variably modified type. If Ty is a VLA, will return the value that
- /// corresponds to the size in bytes of the VLA type. Will return 0 otherwise.
+ /// emitArrayLength - Compute the length of an array, even if it's a
+ /// VLA, and drill down to the base element type.
+ llvm::Value *emitArrayLength(const ArrayType *arrayType,
+ QualType &baseType,
+ llvm::Value *&addr);
+
+ /// EmitVLASize - Capture all the sizes for the VLA expressions in
+ /// the given variably-modified type and store them in the VLASizeMap.
///
/// This function can be called with a null (unreachable) insert point.
- llvm::Value *EmitVLASize(QualType Ty);
+ void EmitVariablyModifiedType(QualType Ty);
- // GetVLASize - Returns an LLVM value that corresponds to the size in bytes
- // of a variable length array type.
- llvm::Value *GetVLASize(const VariableArrayType *);
+ /// getVLASize - Returns an LLVM value that corresponds to the size,
+ /// in non-variably-sized elements, of a variable length array type,
+ /// plus that largest non-variably-sized element type. Assumes that
+ /// the type has already been emitted with EmitVariablyModifiedType.
+ std::pair<llvm::Value*,QualType> getVLASize(const VariableArrayType *vla);
+ std::pair<llvm::Value*,QualType> getVLASize(QualType vla);
/// LoadCXXThis - Load the value of 'this'. This function is only valid while
/// generating code for an C++ member function.
@@ -1535,17 +1703,7 @@ public:
CallExpr::const_arg_iterator ArgEnd,
bool ZeroInitialization = false);
- void EmitCXXAggrDestructorCall(const CXXDestructorDecl *D,
- const ArrayType *Array,
- llvm::Value *This);
-
- void EmitCXXAggrDestructorCall(const CXXDestructorDecl *D,
- llvm::Value *NumElements,
- llvm::Value *This);
-
- llvm::Function *GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D,
- const ArrayType *Array,
- llvm::Value *This);
+ static Destroyer destroyCXXObject;
void EmitCXXDestructorCall(const CXXDestructorDecl *D, CXXDtorType Type,
bool ForVirtualBase, llvm::Value *This);
@@ -1584,6 +1742,10 @@ public:
/// This function can be called with a null (unreachable) insert point.
void EmitVarDecl(const VarDecl &D);
+ void EmitScalarInit(const Expr *init, const ValueDecl *D,
+ LValue lvalue, bool capturedByInit);
+ void EmitScalarInit(llvm::Value *init, LValue lvalue);
+
typedef void SpecialInitFn(CodeGenFunction &Init, const VarDecl &D,
llvm::Value *Address);
@@ -1639,6 +1801,8 @@ public:
AutoVarEmission EmitAutoVarAlloca(const VarDecl &var);
void EmitAutoVarInit(const AutoVarEmission &emission);
void EmitAutoVarCleanups(const AutoVarEmission &emission);
+ void emitAutoVarTypeCleanup(const AutoVarEmission &emission,
+ QualType::DestructionKind dtorKind);
void EmitStaticVarDecl(const VarDecl &D,
llvm::GlobalValue::LinkageTypes Linkage);
@@ -1709,6 +1873,7 @@ public:
void EmitObjCAtTryStmt(const ObjCAtTryStmt &S);
void EmitObjCAtThrowStmt(const ObjCAtThrowStmt &S);
void EmitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt &S);
+ void EmitObjCAutoreleasePoolStmt(const ObjCAutoreleasePoolStmt &S);
llvm::Constant *getUnwindResumeFn();
llvm::Constant *getUnwindResumeOrRethrowFn();
@@ -1775,6 +1940,12 @@ public:
unsigned Alignment, QualType Ty,
llvm::MDNode *TBAAInfo = 0);
+ /// EmitLoadOfScalar - Load a scalar value from an address, taking
+ /// care to appropriately convert from the memory representation to
+ /// the LLVM value representation. The l-value must be a simple
+ /// l-value.
+ llvm::Value *EmitLoadOfScalar(LValue lvalue);
+
/// EmitStoreOfScalar - Store a scalar value to an address, taking
/// care to appropriately convert from the memory representation to
/// the LLVM value representation.
@@ -1782,21 +1953,26 @@ public:
bool Volatile, unsigned Alignment, QualType Ty,
llvm::MDNode *TBAAInfo = 0);
+ /// EmitStoreOfScalar - Store a scalar value to an address, taking
+ /// care to appropriately convert from the memory representation to
+ /// the LLVM value representation. The l-value must be a simple
+ /// l-value.
+ void EmitStoreOfScalar(llvm::Value *value, LValue lvalue);
+
/// EmitLoadOfLValue - Given an expression that represents a value lvalue,
/// this method emits the address of the lvalue, then loads the result as an
/// rvalue, returning the rvalue.
- RValue EmitLoadOfLValue(LValue V, QualType LVType);
- RValue EmitLoadOfExtVectorElementLValue(LValue V, QualType LVType);
- RValue EmitLoadOfBitfieldLValue(LValue LV, QualType ExprType);
+ RValue EmitLoadOfLValue(LValue V);
+ RValue EmitLoadOfExtVectorElementLValue(LValue V);
+ RValue EmitLoadOfBitfieldLValue(LValue LV);
RValue EmitLoadOfPropertyRefLValue(LValue LV,
ReturnValueSlot Return = ReturnValueSlot());
/// EmitStoreThroughLValue - Store the specified rvalue into the specified
/// lvalue, where both are guaranteed to the have the same type, and that type
/// is 'Ty'.
- void EmitStoreThroughLValue(RValue Src, LValue Dst, QualType Ty);
- void EmitStoreThroughExtVectorComponentLValue(RValue Src, LValue Dst,
- QualType Ty);
+ void EmitStoreThroughLValue(RValue Src, LValue Dst);
+ void EmitStoreThroughExtVectorComponentLValue(RValue Src, LValue Dst);
void EmitStoreThroughPropertyRefLValue(RValue Src, LValue Dst);
/// EmitStoreThroughLValue - Store Src into Dst with same constraints as
@@ -1805,7 +1981,7 @@ public:
/// \param Result [out] - If non-null, this will be set to a Value* for the
/// bit-field contents after the store, appropriate for use as the result of
/// an assignment to the bit-field.
- void EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst, QualType Ty,
+ void EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst,
llvm::Value **Result=0);
/// Emit an l-value for an assignment (simple or compound) of complex type.
@@ -1832,6 +2008,7 @@ public:
LValue EmitConditionalOperatorLValue(const AbstractConditionalOperator *E);
LValue EmitCastLValue(const CastExpr *E);
LValue EmitNullInitializationLValue(const CXXScalarValueInitExpr *E);
+ LValue EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E);
LValue EmitOpaqueValueLValue(const OpaqueValueExpr *e);
llvm::Value *EmitIvarOffset(const ObjCInterfaceDecl *Interface,
@@ -1897,8 +2074,9 @@ public:
ReturnValueSlot ReturnValue = ReturnValueSlot());
llvm::CallSite EmitCallOrInvoke(llvm::Value *Callee,
- llvm::Value * const *ArgBegin,
- llvm::Value * const *ArgEnd,
+ llvm::ArrayRef<llvm::Value *> Args,
+ const llvm::Twine &Name = "");
+ llvm::CallSite EmitCallOrInvoke(llvm::Value *Callee,
const llvm::Twine &Name = "");
llvm::Value *BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *This,
@@ -1961,6 +2139,59 @@ public:
RValue EmitObjCMessageExpr(const ObjCMessageExpr *E,
ReturnValueSlot Return = ReturnValueSlot());
+ /// Retrieves the default cleanup kind for an ARC cleanup.
+ /// Except under -fobjc-arc-eh, ARC cleanups are normal-only.
+ CleanupKind getARCCleanupKind() {
+ return CGM.getCodeGenOpts().ObjCAutoRefCountExceptions
+ ? NormalAndEHCleanup : NormalCleanup;
+ }
+
+ // ARC primitives.
+ void EmitARCInitWeak(llvm::Value *value, llvm::Value *addr);
+ void EmitARCDestroyWeak(llvm::Value *addr);
+ llvm::Value *EmitARCLoadWeak(llvm::Value *addr);
+ llvm::Value *EmitARCLoadWeakRetained(llvm::Value *addr);
+ llvm::Value *EmitARCStoreWeak(llvm::Value *value, llvm::Value *addr,
+ bool ignored);
+ void EmitARCCopyWeak(llvm::Value *dst, llvm::Value *src);
+ void EmitARCMoveWeak(llvm::Value *dst, llvm::Value *src);
+ llvm::Value *EmitARCRetainAutorelease(QualType type, llvm::Value *value);
+ llvm::Value *EmitARCRetainAutoreleaseNonBlock(llvm::Value *value);
+ llvm::Value *EmitARCStoreStrong(LValue lvalue, llvm::Value *value,
+ bool ignored);
+ llvm::Value *EmitARCStoreStrongCall(llvm::Value *addr, llvm::Value *value,
+ bool ignored);
+ llvm::Value *EmitARCRetain(QualType type, llvm::Value *value);
+ llvm::Value *EmitARCRetainNonBlock(llvm::Value *value);
+ llvm::Value *EmitARCRetainBlock(llvm::Value *value);
+ void EmitARCRelease(llvm::Value *value, bool precise);
+ llvm::Value *EmitARCAutorelease(llvm::Value *value);
+ llvm::Value *EmitARCAutoreleaseReturnValue(llvm::Value *value);
+ llvm::Value *EmitARCRetainAutoreleaseReturnValue(llvm::Value *value);
+ llvm::Value *EmitARCRetainAutoreleasedReturnValue(llvm::Value *value);
+
+ std::pair<LValue,llvm::Value*>
+ EmitARCStoreAutoreleasing(const BinaryOperator *e);
+ std::pair<LValue,llvm::Value*>
+ EmitARCStoreStrong(const BinaryOperator *e, bool ignored);
+
+ llvm::Value *EmitObjCProduceObject(QualType T, llvm::Value *Ptr);
+ llvm::Value *EmitObjCConsumeObject(QualType T, llvm::Value *Ptr);
+ llvm::Value *EmitObjCExtendObjectLifetime(QualType T, llvm::Value *Ptr);
+
+ llvm::Value *EmitARCRetainScalarExpr(const Expr *expr);
+ llvm::Value *EmitARCRetainAutoreleaseScalarExpr(const Expr *expr);
+
+ static Destroyer destroyARCStrongImprecise;
+ static Destroyer destroyARCStrongPrecise;
+ static Destroyer destroyARCWeak;
+
+ void EmitObjCAutoreleasePoolPop(llvm::Value *Ptr);
+ llvm::Value *EmitObjCAutoreleasePoolPush();
+ llvm::Value *EmitObjCMRRAutoreleasePoolPush();
+ void EmitObjCAutoreleasePoolCleanup(llvm::Value *Ptr);
+ void EmitObjCMRRAutoreleasePoolPop(llvm::Value *Ptr);
+
/// EmitReferenceBindingToExpr - Emits a reference binding to the passed in
/// expression. Will emit a temporary variable if E is not an LValue.
RValue EmitReferenceBindingToExpr(const Expr* E,
@@ -2002,6 +2233,10 @@ public:
void EmitGCMemmoveCollectable(llvm::Value *DestPtr, llvm::Value *SrcPtr,
QualType Ty);
+ /// EmitExtendGCLifetime - Given a pointer to an Objective-C object,
+ /// make sure it survives garbage collection until this point.
+ void EmitExtendGCLifetime(llvm::Value *object);
+
/// EmitComplexExpr - Emit the computation of the specified expression of
/// complex type, returning the result.
ComplexPairTy EmitComplexExpr(const Expr *E,
@@ -2135,7 +2370,8 @@ private:
/// Ty, into individual arguments on the provided vector \arg Args. See
/// ABIArgInfo::Expand.
void ExpandTypeToArgs(QualType Ty, RValue Src,
- llvm::SmallVector<llvm::Value*, 16> &Args);
+ llvm::SmallVector<llvm::Value*, 16> &Args,
+ llvm::FunctionType *IRFuncTy);
llvm::Value* EmitAsmInput(const AsmStmt &S,
const TargetInfo::ConstraintInfo &Info,
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 7a1a968259f3..0668039a892c 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -62,9 +62,9 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
: Context(C), Features(C.getLangOptions()), CodeGenOpts(CGO), TheModule(M),
TheTargetData(TD), TheTargetCodeGenInfo(0), Diags(diags),
ABI(createCXXABI(*this)),
- Types(C, M, TD, getTargetCodeGenInfo().getABIInfo(), ABI),
+ Types(C, M, TD, getTargetCodeGenInfo().getABIInfo(), ABI, CGO),
TBAA(0),
- VTables(*this), Runtime(0), DebugInfo(0),
+ VTables(*this), Runtime(0), DebugInfo(0), ARCData(0), RRData(0),
CFConstantStringClassRef(0), ConstantStringClassRef(0),
VMContext(M.getContext()),
NSConcreteGlobalBlockDecl(0), NSConcreteStackBlockDecl(0),
@@ -88,6 +88,10 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
Block.GlobalUniqueCount = 0;
+ if (C.getLangOptions().ObjCAutoRefCount)
+ ARCData = new ARCEntrypoints();
+ RRData = new RREntrypoints();
+
// Initialize the type cache.
llvm::LLVMContext &LLVMContext = M.getContext();
VoidTy = llvm::Type::getVoidTy(LLVMContext);
@@ -108,6 +112,8 @@ CodeGenModule::~CodeGenModule() {
delete &ABI;
delete TBAA;
delete DebugInfo;
+ delete ARCData;
+ delete RRData;
}
void CodeGenModule::createObjCRuntime() {
@@ -190,6 +196,10 @@ void CodeGenModule::ErrorUnsupported(const Decl *D, const char *Type,
getDiags().Report(Context.getFullLoc(D->getLocation()), DiagID) << Msg;
}
+llvm::ConstantInt *CodeGenModule::getSize(CharUnits size) {
+ return llvm::ConstantInt::get(SizeTy, size.getQuantity());
+}
+
void CodeGenModule::setGlobalVisibility(llvm::GlobalValue *GV,
const NamedDecl *D) const {
// Internal definitions always have default visibility.
@@ -347,8 +357,8 @@ void CodeGenModule::EmitCtorList(const CtorList &Fns, const char *GlobalName) {
llvm::Type *CtorPFTy = llvm::PointerType::getUnqual(CtorFTy);
// Get the type of a ctor entry, { i32, void ()* }.
- llvm::StructType* CtorStructTy =
- llvm::StructType::get(VMContext, llvm::Type::getInt32Ty(VMContext),
+ llvm::StructType *CtorStructTy =
+ llvm::StructType::get(llvm::Type::getInt32Ty(VMContext),
llvm::PointerType::getUnqual(CtorFTy), NULL);
// Construct the constructor and destructor arrays.
@@ -670,7 +680,7 @@ llvm::Constant *CodeGenModule::EmitAnnotateAttr(llvm::GlobalValue *GV,
llvm::ConstantExpr::getBitCast(unitGV, SBP),
llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), LineNo)
};
- return llvm::ConstantStruct::get(VMContext, Fields, 4, false);
+ return llvm::ConstantStruct::getAnon(Fields);
}
bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) {
@@ -830,7 +840,8 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) {
llvm::Constant *
CodeGenModule::GetOrCreateLLVMFunction(llvm::StringRef MangledName,
const llvm::Type *Ty,
- GlobalDecl D, bool ForVTable) {
+ GlobalDecl D, bool ForVTable,
+ llvm::Attributes ExtraAttrs) {
// Lookup the entry, lazily creating it if necessary.
llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
if (Entry) {
@@ -846,8 +857,7 @@ CodeGenModule::GetOrCreateLLVMFunction(llvm::StringRef MangledName,
return Entry;
// Make sure the result is of the correct type.
- const llvm::Type *PTy = llvm::PointerType::getUnqual(Ty);
- return llvm::ConstantExpr::getBitCast(Entry, PTy);
+ return llvm::ConstantExpr::getBitCast(Entry, Ty->getPointerTo());
}
// This function doesn't have a complete type (for example, the return
@@ -869,6 +879,8 @@ CodeGenModule::GetOrCreateLLVMFunction(llvm::StringRef MangledName,
assert(F->getName() == MangledName && "name was uniqued!");
if (D.getDecl())
SetFunctionAttributes(D, F, IsIncompleteFunction);
+ if (ExtraAttrs != llvm::Attribute::None)
+ F->addFnAttr(ExtraAttrs);
// This is the first use or definition of a mangled name. If there is a
// deferred decl with this name, remember that we need to emit it at the end
@@ -915,7 +927,7 @@ CodeGenModule::GetOrCreateLLVMFunction(llvm::StringRef MangledName,
return F;
}
- const llvm::Type *PTy = llvm::PointerType::getUnqual(Ty);
+ llvm::Type *PTy = llvm::PointerType::getUnqual(Ty);
return llvm::ConstantExpr::getBitCast(F, PTy);
}
@@ -937,8 +949,10 @@ llvm::Constant *CodeGenModule::GetAddrOfFunction(GlobalDecl GD,
/// type and name.
llvm::Constant *
CodeGenModule::CreateRuntimeFunction(const llvm::FunctionType *FTy,
- llvm::StringRef Name) {
- return GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(), /*ForVTable=*/false);
+ llvm::StringRef Name,
+ llvm::Attributes ExtraAttrs) {
+ return GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(), /*ForVTable=*/false,
+ ExtraAttrs);
}
static bool DeclIsConstantGlobal(ASTContext &Context, const VarDecl *D,
@@ -1340,7 +1354,8 @@ CodeGenModule::GetLLVMLinkageVarDefinition(const VarDecl *D,
((!CodeGenOpts.NoCommon && !D->getAttr<NoCommonAttr>()) ||
D->getAttr<CommonAttr>()) &&
!D->hasExternalStorage() && !D->getInit() &&
- !D->getAttr<SectionAttr>() && !D->isThreadSpecified()) {
+ !D->getAttr<SectionAttr>() && !D->isThreadSpecified() &&
+ !D->getAttr<WeakImportAttr>()) {
// Thread local vars aren't considered common linkage.
return llvm::GlobalVariable::CommonLinkage;
}
@@ -1398,8 +1413,7 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old,
// Okay, we can transform this. Create the new call instruction and copy
// over the required information.
ArgList.append(CS.arg_begin(), CS.arg_begin() + ArgNo);
- llvm::CallInst *NewCall = llvm::CallInst::Create(NewFn, ArgList.begin(),
- ArgList.end(), "", CI);
+ llvm::CallInst *NewCall = llvm::CallInst::Create(NewFn, ArgList, "", CI);
ArgList.clear();
if (!NewCall->getType()->isVoidTy())
NewCall->takeName(CI);
@@ -1426,7 +1440,7 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) {
bool variadic = false;
if (const FunctionProtoType *fpt = D->getType()->getAs<FunctionProtoType>())
variadic = fpt->isVariadic();
- const llvm::FunctionType *Ty = getTypes().GetFunctionType(FI, variadic, false);
+ const llvm::FunctionType *Ty = getTypes().GetFunctionType(FI, variadic);
// Get or create the prototype for the function.
llvm::Constant *Entry = GetAddrOfFunction(GD, Ty);
@@ -1597,10 +1611,10 @@ llvm::Value *CodeGenModule::getBuiltinLibFunction(const FunctionDecl *FD,
return GetOrCreateLLVMFunction(Name, Ty, D, /*ForVTable=*/false);
}
-llvm::Function *CodeGenModule::getIntrinsic(unsigned IID,const llvm::Type **Tys,
- unsigned NumTys) {
- return llvm::Intrinsic::getDeclaration(&getModule(),
- (llvm::Intrinsic::ID)IID, Tys, NumTys);
+llvm::Function *CodeGenModule::getIntrinsic(unsigned IID,
+ llvm::ArrayRef<llvm::Type*> Tys) {
+ return llvm::Intrinsic::getDeclaration(&getModule(), (llvm::Intrinsic::ID)IID,
+ Tys);
}
static llvm::StringMapEntry<llvm::Constant*> &
@@ -1997,6 +2011,7 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) {
false, true, false, ObjCMethodDecl::Required);
D->addInstanceMethod(DTORMethod);
CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, DTORMethod, false);
+ D->setHasCXXStructors(true);
}
// If the implementation doesn't have any ivar initializers, we don't need
@@ -2015,6 +2030,7 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) {
ObjCMethodDecl::Required);
D->addInstanceMethod(CTORMethod);
CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, CTORMethod, true);
+ D->setHasCXXStructors(true);
}
/// EmitNamespace - Emit all declarations in a namespace.
@@ -2276,7 +2292,7 @@ llvm::Constant *CodeGenModule::getBlockObjectDispose() {
}
// Otherwise construct the function by hand.
- const llvm::Type *args[] = { Int8PtrTy, Int32Ty };
+ llvm::Type *args[] = { Int8PtrTy, Int32Ty };
const llvm::FunctionType *fty
= llvm::FunctionType::get(VoidTy, args, false);
return BlockObjectDispose =
@@ -2295,7 +2311,7 @@ llvm::Constant *CodeGenModule::getBlockObjectAssign() {
}
// Otherwise construct the function by hand.
- const llvm::Type *args[] = { Int8PtrTy, Int8PtrTy, Int32Ty };
+ llvm::Type *args[] = { Int8PtrTy, Int8PtrTy, Int32Ty };
const llvm::FunctionType *fty
= llvm::FunctionType::get(VoidTy, args, false);
return BlockObjectAssign =
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index 779a3523b7f6..86fb6d4d030e 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -19,10 +19,10 @@
#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/GlobalDecl.h"
#include "clang/AST/Mangle.h"
#include "CGVTables.h"
#include "CodeGenTypes.h"
-#include "GlobalDecl.h"
#include "llvm/Module.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringMap.h"
@@ -33,6 +33,7 @@
namespace llvm {
class Module;
class Constant;
+ class ConstantInt;
class Function;
class GlobalValue;
class TargetData;
@@ -98,31 +99,31 @@ namespace CodeGen {
struct CodeGenTypeCache {
/// void
- const llvm::Type *VoidTy;
+ llvm::Type *VoidTy;
/// i8, i32, and i64
- const llvm::IntegerType *Int8Ty, *Int32Ty, *Int64Ty;
+ llvm::IntegerType *Int8Ty, *Int32Ty, *Int64Ty;
/// int
- const llvm::IntegerType *IntTy;
+ llvm::IntegerType *IntTy;
/// intptr_t, size_t, and ptrdiff_t, which we assume are the same size.
union {
- const llvm::IntegerType *IntPtrTy;
- const llvm::IntegerType *SizeTy;
- const llvm::IntegerType *PtrDiffTy;
+ llvm::IntegerType *IntPtrTy;
+ llvm::IntegerType *SizeTy;
+ llvm::IntegerType *PtrDiffTy;
};
/// void* in address space 0
union {
- const llvm::PointerType *VoidPtrTy;
- const llvm::PointerType *Int8PtrTy;
+ llvm::PointerType *VoidPtrTy;
+ llvm::PointerType *Int8PtrTy;
};
/// void** in address space 0
union {
- const llvm::PointerType *VoidPtrPtrTy;
- const llvm::PointerType *Int8PtrPtrTy;
+ llvm::PointerType *VoidPtrPtrTy;
+ llvm::PointerType *Int8PtrPtrTy;
};
/// The width of a pointer into the generic address space.
@@ -131,6 +132,71 @@ namespace CodeGen {
/// The alignment of a pointer into the generic address space.
unsigned char PointerAlignInBytes;
};
+
+struct RREntrypoints {
+ RREntrypoints() { memset(this, 0, sizeof(*this)); }
+ /// void objc_autoreleasePoolPop(void*);
+ llvm::Constant *objc_autoreleasePoolPop;
+
+ /// void *objc_autoreleasePoolPush(void);
+ llvm::Constant *objc_autoreleasePoolPush;
+};
+
+struct ARCEntrypoints {
+ ARCEntrypoints() { memset(this, 0, sizeof(*this)); }
+
+ /// id objc_autorelease(id);
+ llvm::Constant *objc_autorelease;
+
+ /// id objc_autoreleaseReturnValue(id);
+ llvm::Constant *objc_autoreleaseReturnValue;
+
+ /// void objc_copyWeak(id *dest, id *src);
+ llvm::Constant *objc_copyWeak;
+
+ /// void objc_destroyWeak(id*);
+ llvm::Constant *objc_destroyWeak;
+
+ /// id objc_initWeak(id*, id);
+ llvm::Constant *objc_initWeak;
+
+ /// id objc_loadWeak(id*);
+ llvm::Constant *objc_loadWeak;
+
+ /// id objc_loadWeakRetained(id*);
+ llvm::Constant *objc_loadWeakRetained;
+
+ /// void objc_moveWeak(id *dest, id *src);
+ llvm::Constant *objc_moveWeak;
+
+ /// id objc_retain(id);
+ llvm::Constant *objc_retain;
+
+ /// id objc_retainAutorelease(id);
+ llvm::Constant *objc_retainAutorelease;
+
+ /// id objc_retainAutoreleaseReturnValue(id);
+ llvm::Constant *objc_retainAutoreleaseReturnValue;
+
+ /// id objc_retainAutoreleasedReturnValue(id);
+ llvm::Constant *objc_retainAutoreleasedReturnValue;
+
+ /// id objc_retainBlock(id);
+ llvm::Constant *objc_retainBlock;
+
+ /// void objc_release(id);
+ llvm::Constant *objc_release;
+
+ /// id objc_storeStrong(id*, id);
+ llvm::Constant *objc_storeStrong;
+
+ /// id objc_storeWeak(id*, id);
+ llvm::Constant *objc_storeWeak;
+
+ /// A void(void) inline asm to use to mark that the return value of
+ /// a call will be immediately retain.
+ llvm::InlineAsm *retainAutoreleasedReturnValueMarker;
+};
/// CodeGenModule - This class organizes the cross-function state that is used
/// while generating LLVM code.
@@ -157,6 +223,8 @@ class CodeGenModule : public CodeGenTypeCache {
CGObjCRuntime* Runtime;
CGDebugInfo* DebugInfo;
+ ARCEntrypoints *ARCData;
+ RREntrypoints *RRData;
// WeakRefReferences - A set of references that have only been seen via
// a weakref so far. This is used to remove the weak of the reference if we ever
@@ -244,8 +312,8 @@ class CodeGenModule : public CodeGenTypeCache {
llvm::Constant *BlockObjectAssign;
llvm::Constant *BlockObjectDispose;
- const llvm::Type *BlockDescriptorType;
- const llvm::Type *GenericBlockLiteralType;
+ llvm::Type *BlockDescriptorType;
+ llvm::Type *GenericBlockLiteralType;
struct {
int GlobalUniqueCount;
@@ -275,6 +343,16 @@ public:
/// getCXXABI() - Return a reference to the configured C++ ABI.
CGCXXABI &getCXXABI() { return ABI; }
+ ARCEntrypoints &getARCEntrypoints() const {
+ assert(getLangOptions().ObjCAutoRefCount && ARCData != 0);
+ return *ARCData;
+ }
+
+ RREntrypoints &getRREntrypoints() const {
+ assert(RRData != 0);
+ return *RRData;
+ }
+
llvm::Value *getStaticLocalDeclAddress(const VarDecl *VD) {
return StaticLocalDeclMap[VD];
}
@@ -305,6 +383,9 @@ public:
static void DecorateInstruction(llvm::Instruction *Inst,
llvm::MDNode *TBAAInfo);
+ /// getSize - Emit the given number of characters as a value of type size_t.
+ llvm::ConstantInt *getSize(CharUnits numChars);
+
/// setGlobalVisibility - Set the visibility for the given LLVM
/// GlobalValue.
void setGlobalVisibility(llvm::GlobalValue *GV, const NamedDecl *D) const;
@@ -422,10 +503,10 @@ public:
/// getBlockDescriptorType - Fetches the type of a generic block
/// descriptor.
- const llvm::Type *getBlockDescriptorType();
+ llvm::Type *getBlockDescriptorType();
/// getGenericBlockLiteralType - The type of a generic block literal.
- const llvm::Type *getGenericBlockLiteralType();
+ llvm::Type *getGenericBlockLiteralType();
/// GetAddrOfGlobalBlock - Gets the address of a block which
/// requires no captures.
@@ -474,7 +555,7 @@ public:
/// created).
llvm::Constant *GetAddrOfConstantCString(const std::string &str,
const char *GlobalName=0);
-
+
/// GetAddrOfCXXConstructor - Return the address of the constructor of the
/// given type.
llvm::GlobalValue *GetAddrOfCXXConstructor(const CXXConstructorDecl *ctor,
@@ -492,8 +573,8 @@ public:
llvm::Value *getBuiltinLibFunction(const FunctionDecl *FD,
unsigned BuiltinID);
- llvm::Function *getIntrinsic(unsigned IID, const llvm::Type **Tys = 0,
- unsigned NumTys = 0);
+ llvm::Function *getIntrinsic(unsigned IID, llvm::ArrayRef<llvm::Type*> Tys =
+ llvm::ArrayRef<llvm::Type*>());
/// EmitTopLevelDecl - Emit code for a single top level declaration.
void EmitTopLevelDecl(Decl *D);
@@ -514,7 +595,9 @@ public:
/// CreateRuntimeFunction - Create a new runtime function with the specified
/// type and name.
llvm::Constant *CreateRuntimeFunction(const llvm::FunctionType *Ty,
- llvm::StringRef Name);
+ llvm::StringRef Name,
+ llvm::Attributes ExtraAttrs =
+ llvm::Attribute::None);
/// CreateRuntimeVariable - Create a new runtime global variable with the
/// specified type and name.
llvm::Constant *CreateRuntimeVariable(const llvm::Type *Ty,
@@ -642,7 +725,9 @@ private:
llvm::Constant *GetOrCreateLLVMFunction(llvm::StringRef MangledName,
const llvm::Type *Ty,
GlobalDecl D,
- bool ForVTable);
+ bool ForVTable,
+ llvm::Attributes ExtraAttrs =
+ llvm::Attribute::None);
llvm::Constant *GetOrCreateLLVMGlobal(llvm::StringRef MangledName,
const llvm::PointerType *PTy,
const VarDecl *D,
diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
index 8db6fe518684..764688fcb12e 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -28,9 +28,10 @@ using namespace CodeGen;
CodeGenTypes::CodeGenTypes(ASTContext &Ctx, llvm::Module& M,
const llvm::TargetData &TD, const ABIInfo &Info,
- CGCXXABI &CXXABI)
+ CGCXXABI &CXXABI, const CodeGenOptions &CGO)
: Context(Ctx), Target(Ctx.Target), TheModule(M), TheTargetData(TD),
- TheABIInfo(Info), TheCXXABI(CXXABI) {
+ TheABIInfo(Info), TheCXXABI(CXXABI), CodeGenOpts(CGO) {
+ SkippedLayout = false;
}
CodeGenTypes::~CodeGenTypes() {
@@ -44,28 +45,8 @@ CodeGenTypes::~CodeGenTypes() {
delete &*I++;
}
-/// HandleLateResolvedPointers - For top-level ConvertType calls, this handles
-/// pointers that are referenced but have not been converted yet. This is used
-/// to handle cyclic structures properly.
-void CodeGenTypes::HandleLateResolvedPointers() {
- assert(!PointersToResolve.empty() && "No pointers to resolve!");
-
- // Any pointers that were converted deferred evaluation of their pointee type,
- // creating an opaque type instead. This is in order to avoid problems with
- // circular types. Loop through all these defered pointees, if any, and
- // resolve them now.
- while (!PointersToResolve.empty()) {
- std::pair<QualType, llvm::OpaqueType*> P = PointersToResolve.pop_back_val();
-
- // We can handle bare pointers here because we know that the only pointers
- // to the Opaque type are P.second and from other types. Refining the
- // opqaue type away will invalidate P.second, but we don't mind :).
- const llvm::Type *NT = ConvertTypeForMemRecursive(P.first);
- P.second->refineAbstractTypeTo(NT);
- }
-}
-
-void CodeGenTypes::addRecordTypeName(const RecordDecl *RD, const llvm::Type *Ty,
+void CodeGenTypes::addRecordTypeName(const RecordDecl *RD,
+ llvm::StructType *Ty,
llvm::StringRef suffix) {
llvm::SmallString<256> TypeName;
llvm::raw_svector_ostream OS(TypeName);
@@ -93,47 +74,15 @@ void CodeGenTypes::addRecordTypeName(const RecordDecl *RD, const llvm::Type *Ty,
if (!suffix.empty())
OS << suffix;
- TheModule.addTypeName(OS.str(), Ty);
-}
-
-/// ConvertType - Convert the specified type to its LLVM form.
-const llvm::Type *CodeGenTypes::ConvertType(QualType T, bool IsRecursive) {
- const llvm::Type *Result = ConvertTypeRecursive(T);
-
- // If this is a top-level call to ConvertType and sub-conversions caused
- // pointers to get lazily built as opaque types, resolve the pointers, which
- // might cause Result to be merged away.
- if (!IsRecursive && !PointersToResolve.empty()) {
- llvm::PATypeHolder ResultHandle = Result;
- HandleLateResolvedPointers();
- Result = ResultHandle;
- }
- return Result;
-}
-
-const llvm::Type *CodeGenTypes::ConvertTypeRecursive(QualType T) {
- T = Context.getCanonicalType(T);
-
- // See if type is already cached.
- llvm::DenseMap<const Type *, llvm::PATypeHolder>::iterator
- I = TypeCache.find(T.getTypePtr());
- // If type is found in map and this is not a definition for a opaque
- // place holder type then use it. Otherwise, convert type T.
- if (I != TypeCache.end())
- return I->second.get();
-
- const llvm::Type *ResultType = ConvertNewType(T);
- TypeCache.insert(std::make_pair(T.getTypePtr(),
- llvm::PATypeHolder(ResultType)));
- return ResultType;
+ Ty->setName(OS.str());
}
/// ConvertTypeForMem - Convert type T into a llvm::Type. This differs from
/// ConvertType in that it is used to convert to the memory representation for
/// a type. For example, the scalar representation for _Bool is i1, but the
/// memory representation is usually i8 or i32, depending on the target.
-const llvm::Type *CodeGenTypes::ConvertTypeForMem(QualType T, bool IsRecursive){
- const llvm::Type *R = ConvertType(T, IsRecursive);
+llvm::Type *CodeGenTypes::ConvertTypeForMem(QualType T){
+ llvm::Type *R = ConvertType(T);
// If this is a non-bool type, don't map it.
if (!R->isIntegerTy(1))
@@ -142,69 +91,178 @@ const llvm::Type *CodeGenTypes::ConvertTypeForMem(QualType T, bool IsRecursive){
// Otherwise, return an integer of the target-specified size.
return llvm::IntegerType::get(getLLVMContext(),
(unsigned)Context.getTypeSize(T));
+}
+
+/// isRecordLayoutComplete - Return true if the specified type is already
+/// completely laid out.
+bool CodeGenTypes::isRecordLayoutComplete(const Type *Ty) const {
+ llvm::DenseMap<const Type*, llvm::StructType *>::const_iterator I =
+ RecordDeclTypes.find(Ty);
+ return I != RecordDeclTypes.end() && !I->second->isOpaque();
}
-// Code to verify a given function type is complete, i.e. the return type
-// and all of the argument types are complete.
-const TagType *CodeGenTypes::VerifyFuncTypeComplete(const Type* T) {
- const FunctionType *FT = cast<FunctionType>(T);
- if (const TagType* TT = FT->getResultType()->getAs<TagType>())
- if (!TT->getDecl()->isDefinition())
- return TT;
- if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(T))
- for (unsigned i = 0; i < FPT->getNumArgs(); i++)
- if (const TagType* TT = FPT->getArgType(i)->getAs<TagType>())
- if (!TT->getDecl()->isDefinition())
- return TT;
- return 0;
+static bool
+isSafeToConvert(QualType T, CodeGenTypes &CGT,
+ llvm::SmallPtrSet<const RecordDecl*, 16> &AlreadyChecked);
+
+
+/// isSafeToConvert - Return true if it is safe to convert the specified record
+/// decl to IR and lay it out, false if doing so would cause us to get into a
+/// recursive compilation mess.
+static bool
+isSafeToConvert(const RecordDecl *RD, CodeGenTypes &CGT,
+ llvm::SmallPtrSet<const RecordDecl*, 16> &AlreadyChecked) {
+ // If we have already checked this type (maybe the same type is used by-value
+ // multiple times in multiple structure fields, don't check again.
+ if (!AlreadyChecked.insert(RD)) return true;
+
+ const Type *Key = CGT.getContext().getTagDeclType(RD).getTypePtr();
+
+ // If this type is already laid out, converting it is a noop.
+ if (CGT.isRecordLayoutComplete(Key)) return true;
+
+ // If this type is currently being laid out, we can't recursively compile it.
+ if (CGT.isRecordBeingLaidOut(Key))
+ return false;
+
+ // If this type would require laying out bases that are currently being laid
+ // out, don't do it. This includes virtual base classes which get laid out
+ // when a class is translated, even though they aren't embedded by-value into
+ // the class.
+ if (const CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) {
+ for (CXXRecordDecl::base_class_const_iterator I = CRD->bases_begin(),
+ E = CRD->bases_end(); I != E; ++I)
+ if (!isSafeToConvert(I->getType()->getAs<RecordType>()->getDecl(),
+ CGT, AlreadyChecked))
+ return false;
+ }
+
+ // If this type would require laying out members that are currently being laid
+ // out, don't do it.
+ for (RecordDecl::field_iterator I = RD->field_begin(),
+ E = RD->field_end(); I != E; ++I)
+ if (!isSafeToConvert(I->getType(), CGT, AlreadyChecked))
+ return false;
+
+ // If there are no problems, lets do it.
+ return true;
+}
+
+/// isSafeToConvert - Return true if it is safe to convert this field type,
+/// which requires the structure elements contained by-value to all be
+/// recursively safe to convert.
+static bool
+isSafeToConvert(QualType T, CodeGenTypes &CGT,
+ llvm::SmallPtrSet<const RecordDecl*, 16> &AlreadyChecked) {
+ T = T.getCanonicalType();
+
+ // If this is a record, check it.
+ if (const RecordType *RT = dyn_cast<RecordType>(T))
+ return isSafeToConvert(RT->getDecl(), CGT, AlreadyChecked);
+
+ // If this is an array, check the elements, which are embedded inline.
+ if (const ArrayType *AT = dyn_cast<ArrayType>(T))
+ return isSafeToConvert(AT->getElementType(), CGT, AlreadyChecked);
+
+ // Otherwise, there is no concern about transforming this. We only care about
+ // things that are contained by-value in a structure that can have another
+ // structure as a member.
+ return true;
+}
+
+
+/// isSafeToConvert - Return true if it is safe to convert the specified record
+/// decl to IR and lay it out, false if doing so would cause us to get into a
+/// recursive compilation mess.
+static bool isSafeToConvert(const RecordDecl *RD, CodeGenTypes &CGT) {
+ // If no structs are being laid out, we can certainly do this one.
+ if (CGT.noRecordsBeingLaidOut()) return true;
+
+ llvm::SmallPtrSet<const RecordDecl*, 16> AlreadyChecked;
+ return isSafeToConvert(RD, CGT, AlreadyChecked);
+}
+
+
+/// isFuncTypeArgumentConvertible - Return true if the specified type in a
+/// function argument or result position can be converted to an IR type at this
+/// point. This boils down to being whether it is complete, as well as whether
+/// we've temporarily deferred expanding the type because we're in a recursive
+/// context.
+bool CodeGenTypes::isFuncTypeArgumentConvertible(QualType Ty) {
+ // If this isn't a tagged type, we can convert it!
+ const TagType *TT = Ty->getAs<TagType>();
+ if (TT == 0) return true;
+
+
+ // If it's a tagged type used by-value, but is just a forward decl, we can't
+ // convert it. Note that getDefinition()==0 is not the same as !isDefinition.
+ if (TT->getDecl()->getDefinition() == 0)
+ return false;
+
+ // If this is an enum, then it is always safe to convert.
+ const RecordType *RT = dyn_cast<RecordType>(TT);
+ if (RT == 0) return true;
+
+ // Otherwise, we have to be careful. If it is a struct that we're in the
+ // process of expanding, then we can't convert the function type. That's ok
+ // though because we must be in a pointer context under the struct, so we can
+ // just convert it to a dummy type.
+ //
+ // We decide this by checking whether ConvertRecordDeclType returns us an
+ // opaque type for a struct that we know is defined.
+ return isSafeToConvert(RT->getDecl(), *this);
+}
+
+
+/// Code to verify a given function type is complete, i.e. the return type
+/// and all of the argument types are complete. Also check to see if we are in
+/// a RS_StructPointer context, and if so whether any struct types have been
+/// pended. If so, we don't want to ask the ABI lowering code to handle a type
+/// that cannot be converted to an IR type.
+bool CodeGenTypes::isFuncTypeConvertible(const FunctionType *FT) {
+ if (!isFuncTypeArgumentConvertible(FT->getResultType()))
+ return false;
+
+ if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FT))
+ for (unsigned i = 0, e = FPT->getNumArgs(); i != e; i++)
+ if (!isFuncTypeArgumentConvertible(FPT->getArgType(i)))
+ return false;
+
+ return true;
}
/// UpdateCompletedType - When we find the full definition for a TagDecl,
/// replace the 'opaque' type we previously made for it if applicable.
void CodeGenTypes::UpdateCompletedType(const TagDecl *TD) {
- const Type *Key = Context.getTagDeclType(TD).getTypePtr();
- llvm::DenseMap<const Type*, llvm::PATypeHolder>::iterator TDTI =
- TagDeclTypes.find(Key);
- if (TDTI == TagDeclTypes.end()) return;
-
- // Remember the opaque LLVM type for this tagdecl.
- llvm::PATypeHolder OpaqueHolder = TDTI->second;
- assert(isa<llvm::OpaqueType>(OpaqueHolder.get()) &&
- "Updating compilation of an already non-opaque type?");
-
- // Remove it from TagDeclTypes so that it will be regenerated.
- TagDeclTypes.erase(TDTI);
-
- // Generate the new type.
- const llvm::Type *NT = ConvertTagDeclType(TD);
-
- // Refine the old opaque type to its new definition.
- cast<llvm::OpaqueType>(OpaqueHolder.get())->refineAbstractTypeTo(NT);
-
- // Since we just completed a tag type, check to see if any function types
- // were completed along with the tag type.
- // FIXME: This is very inefficient; if we track which function types depend
- // on which tag types, though, it should be reasonably efficient.
- llvm::DenseMap<const Type*, llvm::PATypeHolder>::iterator i;
- for (i = FunctionTypes.begin(); i != FunctionTypes.end(); ++i) {
- if (const TagType* TT = VerifyFuncTypeComplete(i->first)) {
- // This function type still depends on an incomplete tag type; make sure
- // that tag type has an associated opaque type.
- ConvertTagDeclType(TT->getDecl());
- } else {
- // This function no longer depends on an incomplete tag type; create the
- // function type, and refine the opaque type to the new function type.
- llvm::PATypeHolder OpaqueHolder = i->second;
- const llvm::Type *NFT = ConvertNewType(QualType(i->first, 0));
- cast<llvm::OpaqueType>(OpaqueHolder.get())->refineAbstractTypeTo(NFT);
- FunctionTypes.erase(i);
+ // If this is an enum being completed, then we flush all non-struct types from
+ // the cache. This allows function types and other things that may be derived
+ // from the enum to be recomputed.
+ if (const EnumDecl *ED = dyn_cast<EnumDecl>(TD)) {
+ // Only flush the cache if we've actually already converted this type.
+ if (TypeCache.count(ED->getTypeForDecl())) {
+ // Okay, we formed some types based on this. We speculated that the enum
+ // would be lowered to i32, so we only need to flush the cache if this
+ // didn't happen.
+ if (!ConvertType(ED->getIntegerType())->isIntegerTy(32))
+ TypeCache.clear();
}
+ return;
}
+
+ // If we completed a RecordDecl that we previously used and converted to an
+ // anonymous type, then go ahead and complete it now.
+ const RecordDecl *RD = cast<RecordDecl>(TD);
+ if (RD->isDependentType()) return;
+
+ // Only complete it if we converted it already. If we haven't converted it
+ // yet, we'll just do it lazily.
+ if (RecordDeclTypes.count(Context.getTagDeclType(RD).getTypePtr()))
+ ConvertRecordDeclType(RD);
}
-static const llvm::Type* getTypeForFormat(llvm::LLVMContext &VMContext,
- const llvm::fltSemantics &format) {
+static llvm::Type *getTypeForFormat(llvm::LLVMContext &VMContext,
+ const llvm::fltSemantics &format) {
if (&format == &llvm::APFloat::IEEEsingle)
return llvm::Type::getFloatTy(VMContext);
if (&format == &llvm::APFloat::IEEEdouble)
@@ -219,10 +277,26 @@ static const llvm::Type* getTypeForFormat(llvm::LLVMContext &VMContext,
return 0;
}
-const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {
- const clang::Type &Ty = *Context.getCanonicalType(T).getTypePtr();
+/// ConvertType - Convert the specified type to its LLVM form.
+llvm::Type *CodeGenTypes::ConvertType(QualType T) {
+ T = Context.getCanonicalType(T);
+
+ const Type *Ty = T.getTypePtr();
- switch (Ty.getTypeClass()) {
+ // RecordTypes are cached and processed specially.
+ if (const RecordType *RT = dyn_cast<RecordType>(Ty))
+ return ConvertRecordDeclType(RT->getDecl());
+
+ // See if type is already cached.
+ llvm::DenseMap<const Type *, llvm::Type *>::iterator TCI = TypeCache.find(Ty);
+ // If type is found in map then use it. Otherwise, convert type T.
+ if (TCI != TypeCache.end())
+ return TCI->second;
+
+ // If we don't have it in the cache, convert it now.
+ llvm::Type *ResultType = 0;
+ switch (Ty->getTypeClass()) {
+ case Type::Record: // Handled above.
#define TYPE(Class, Base)
#define ABSTRACT_TYPE(Class, Base)
#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
@@ -233,18 +307,20 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {
break;
case Type::Builtin: {
- switch (cast<BuiltinType>(Ty).getKind()) {
+ switch (cast<BuiltinType>(Ty)->getKind()) {
case BuiltinType::Void:
case BuiltinType::ObjCId:
case BuiltinType::ObjCClass:
case BuiltinType::ObjCSel:
// LLVM void type can only be used as the result of a function call. Just
// map to the same as char.
- return llvm::Type::getInt8Ty(getLLVMContext());
+ ResultType = llvm::Type::getInt8Ty(getLLVMContext());
+ break;
case BuiltinType::Bool:
// Note that we always return bool as i1 for use as a scalar type.
- return llvm::Type::getInt1Ty(getLLVMContext());
+ ResultType = llvm::Type::getInt1Ty(getLLVMContext());
+ break;
case BuiltinType::Char_S:
case BuiltinType::Char_U:
@@ -262,24 +338,26 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {
case BuiltinType::WChar_U:
case BuiltinType::Char16:
case BuiltinType::Char32:
- return llvm::IntegerType::get(getLLVMContext(),
- static_cast<unsigned>(Context.getTypeSize(T)));
+ ResultType = llvm::IntegerType::get(getLLVMContext(),
+ static_cast<unsigned>(Context.getTypeSize(T)));
+ break;
case BuiltinType::Float:
case BuiltinType::Double:
case BuiltinType::LongDouble:
- return getTypeForFormat(getLLVMContext(),
- Context.getFloatTypeSemantics(T));
+ ResultType = getTypeForFormat(getLLVMContext(),
+ Context.getFloatTypeSemantics(T));
+ break;
- case BuiltinType::NullPtr: {
+ case BuiltinType::NullPtr:
// Model std::nullptr_t as i8*
- const llvm::Type *Ty = llvm::Type::getInt8Ty(getLLVMContext());
- return llvm::PointerType::getUnqual(Ty);
- }
+ ResultType = llvm::Type::getInt8PtrTy(getLLVMContext());
+ break;
case BuiltinType::UInt128:
case BuiltinType::Int128:
- return llvm::IntegerType::get(getLLVMContext(), 128);
+ ResultType = llvm::IntegerType::get(getLLVMContext(), 128);
+ break;
case BuiltinType::Overload:
case BuiltinType::Dependent:
@@ -288,107 +366,145 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {
llvm_unreachable("Unexpected placeholder builtin type!");
break;
}
- llvm_unreachable("Unknown builtin type!");
break;
}
case Type::Complex: {
- const llvm::Type *EltTy =
- ConvertTypeRecursive(cast<ComplexType>(Ty).getElementType());
- return llvm::StructType::get(TheModule.getContext(), EltTy, EltTy, NULL);
+ llvm::Type *EltTy = ConvertType(cast<ComplexType>(Ty)->getElementType());
+ ResultType = llvm::StructType::get(EltTy, EltTy, NULL);
+ break;
}
case Type::LValueReference:
case Type::RValueReference: {
- const ReferenceType &RTy = cast<ReferenceType>(Ty);
- QualType ETy = RTy.getPointeeType();
- llvm::OpaqueType *PointeeType = llvm::OpaqueType::get(getLLVMContext());
- PointersToResolve.push_back(std::make_pair(ETy, PointeeType));
+ const ReferenceType *RTy = cast<ReferenceType>(Ty);
+ QualType ETy = RTy->getPointeeType();
+ llvm::Type *PointeeType = ConvertTypeForMem(ETy);
unsigned AS = Context.getTargetAddressSpace(ETy);
- return llvm::PointerType::get(PointeeType, AS);
+ ResultType = llvm::PointerType::get(PointeeType, AS);
+ break;
}
case Type::Pointer: {
- const PointerType &PTy = cast<PointerType>(Ty);
- QualType ETy = PTy.getPointeeType();
- llvm::OpaqueType *PointeeType = llvm::OpaqueType::get(getLLVMContext());
- PointersToResolve.push_back(std::make_pair(ETy, PointeeType));
+ const PointerType *PTy = cast<PointerType>(Ty);
+ QualType ETy = PTy->getPointeeType();
+ llvm::Type *PointeeType = ConvertTypeForMem(ETy);
+ if (PointeeType->isVoidTy())
+ PointeeType = llvm::Type::getInt8Ty(getLLVMContext());
unsigned AS = Context.getTargetAddressSpace(ETy);
- return llvm::PointerType::get(PointeeType, AS);
+ ResultType = llvm::PointerType::get(PointeeType, AS);
+ break;
}
case Type::VariableArray: {
- const VariableArrayType &A = cast<VariableArrayType>(Ty);
- assert(A.getIndexTypeCVRQualifiers() == 0 &&
+ const VariableArrayType *A = cast<VariableArrayType>(Ty);
+ assert(A->getIndexTypeCVRQualifiers() == 0 &&
"FIXME: We only handle trivial array types so far!");
// VLAs resolve to the innermost element type; this matches
// the return of alloca, and there isn't any obviously better choice.
- return ConvertTypeForMemRecursive(A.getElementType());
+ ResultType = ConvertTypeForMem(A->getElementType());
+ break;
}
case Type::IncompleteArray: {
- const IncompleteArrayType &A = cast<IncompleteArrayType>(Ty);
- assert(A.getIndexTypeCVRQualifiers() == 0 &&
+ const IncompleteArrayType *A = cast<IncompleteArrayType>(Ty);
+ assert(A->getIndexTypeCVRQualifiers() == 0 &&
"FIXME: We only handle trivial array types so far!");
- // int X[] -> [0 x int]
- return llvm::ArrayType::get(ConvertTypeForMemRecursive(A.getElementType()),
- 0);
+ // int X[] -> [0 x int], unless the element type is not sized. If it is
+ // unsized (e.g. an incomplete struct) just use [0 x i8].
+ ResultType = ConvertTypeForMem(A->getElementType());
+ if (!ResultType->isSized()) {
+ SkippedLayout = true;
+ ResultType = llvm::Type::getInt8Ty(getLLVMContext());
+ }
+ ResultType = llvm::ArrayType::get(ResultType, 0);
+ break;
}
case Type::ConstantArray: {
- const ConstantArrayType &A = cast<ConstantArrayType>(Ty);
- const llvm::Type *EltTy = ConvertTypeForMemRecursive(A.getElementType());
- return llvm::ArrayType::get(EltTy, A.getSize().getZExtValue());
+ const ConstantArrayType *A = cast<ConstantArrayType>(Ty);
+ const llvm::Type *EltTy = ConvertTypeForMem(A->getElementType());
+ ResultType = llvm::ArrayType::get(EltTy, A->getSize().getZExtValue());
+ break;
}
case Type::ExtVector:
case Type::Vector: {
- const VectorType &VT = cast<VectorType>(Ty);
- return llvm::VectorType::get(ConvertTypeRecursive(VT.getElementType()),
- VT.getNumElements());
+ const VectorType *VT = cast<VectorType>(Ty);
+ ResultType = llvm::VectorType::get(ConvertType(VT->getElementType()),
+ VT->getNumElements());
+ break;
}
case Type::FunctionNoProto:
case Type::FunctionProto: {
+ const FunctionType *FT = cast<FunctionType>(Ty);
// First, check whether we can build the full function type. If the
// function type depends on an incomplete type (e.g. a struct or enum), we
- // cannot lower the function type. Instead, turn it into an Opaque pointer
- // and have UpdateCompletedType revisit the function type when/if the opaque
- // argument type is defined.
- if (const TagType *TT = VerifyFuncTypeComplete(&Ty)) {
- // This function's type depends on an incomplete tag type; make sure
- // we have an opaque type corresponding to the tag type.
- ConvertTagDeclType(TT->getDecl());
- // Create an opaque type for this function type, save it, and return it.
- llvm::Type *ResultType = llvm::OpaqueType::get(getLLVMContext());
- FunctionTypes.insert(std::make_pair(&Ty, ResultType));
- return ResultType;
+ // cannot lower the function type.
+ if (!isFuncTypeConvertible(FT)) {
+ // This function's type depends on an incomplete tag type.
+ // Return a placeholder type.
+ ResultType = llvm::StructType::get(getLLVMContext());
+
+ SkippedLayout = true;
+ break;
+ }
+
+ // While we're converting the argument types for a function, we don't want
+ // to recursively convert any pointed-to structs. Converting directly-used
+ // structs is ok though.
+ if (!RecordsBeingLaidOut.insert(Ty)) {
+ ResultType = llvm::StructType::get(getLLVMContext());
+
+ SkippedLayout = true;
+ break;
}
// The function type can be built; call the appropriate routines to
// build it.
const CGFunctionInfo *FI;
bool isVariadic;
- if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(&Ty)) {
+ if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FT)) {
FI = &getFunctionInfo(
- CanQual<FunctionProtoType>::CreateUnsafe(QualType(FPT, 0)),
- true /*Recursive*/);
+ CanQual<FunctionProtoType>::CreateUnsafe(QualType(FPT, 0)));
isVariadic = FPT->isVariadic();
} else {
- const FunctionNoProtoType *FNPT = cast<FunctionNoProtoType>(&Ty);
+ const FunctionNoProtoType *FNPT = cast<FunctionNoProtoType>(FT);
FI = &getFunctionInfo(
- CanQual<FunctionNoProtoType>::CreateUnsafe(QualType(FNPT, 0)),
- true /*Recursive*/);
+ CanQual<FunctionNoProtoType>::CreateUnsafe(QualType(FNPT, 0)));
isVariadic = true;
}
+
+ // If there is something higher level prodding our CGFunctionInfo, then
+ // don't recurse into it again.
+ if (FunctionsBeingProcessed.count(FI)) {
+
+ ResultType = llvm::StructType::get(getLLVMContext());
+ SkippedLayout = true;
+ } else {
- return GetFunctionType(*FI, isVariadic, true);
+ // Otherwise, we're good to go, go ahead and convert it.
+ ResultType = GetFunctionType(*FI, isVariadic);
+ }
+
+ RecordsBeingLaidOut.erase(Ty);
+
+ if (SkippedLayout)
+ TypeCache.clear();
+
+ if (RecordsBeingLaidOut.empty())
+ while (!DeferredRecords.empty())
+ ConvertRecordDeclType(DeferredRecords.pop_back_val());
+ break;
}
case Type::ObjCObject:
- return ConvertTypeRecursive(cast<ObjCObjectType>(Ty).getBaseType());
+ ResultType = ConvertType(cast<ObjCObjectType>(Ty)->getBaseType());
+ break;
case Type::ObjCInterface: {
// Objective-C interfaces are always opaque (outside of the
// runtime, which can do whatever it likes); we never refine
// these.
- const llvm::Type *&T = InterfaceTypes[cast<ObjCInterfaceType>(&Ty)];
+ llvm::Type *&T = InterfaceTypes[cast<ObjCInterfaceType>(Ty)];
if (!T)
- T = llvm::OpaqueType::get(getLLVMContext());
- return T;
+ T = llvm::StructType::createNamed(getLLVMContext(), "");
+ ResultType = T;
+ break;
}
case Type::ObjCObjectPointer: {
@@ -396,103 +512,105 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {
// pointer to the underlying interface type. We don't need to worry about
// recursive conversion.
const llvm::Type *T =
- ConvertTypeRecursive(cast<ObjCObjectPointerType>(Ty).getPointeeType());
- return llvm::PointerType::getUnqual(T);
+ ConvertType(cast<ObjCObjectPointerType>(Ty)->getPointeeType());
+ ResultType = T->getPointerTo();
+ break;
}
- case Type::Record:
case Type::Enum: {
- const TagDecl *TD = cast<TagType>(Ty).getDecl();
- const llvm::Type *Res = ConvertTagDeclType(TD);
-
- if (const RecordDecl *RD = dyn_cast<RecordDecl>(TD))
- addRecordTypeName(RD, Res, llvm::StringRef());
- return Res;
+ const EnumDecl *ED = cast<EnumType>(Ty)->getDecl();
+ if (ED->isDefinition() || ED->isFixed())
+ return ConvertType(ED->getIntegerType());
+ // Return a placeholder 'i32' type. This can be changed later when the
+ // type is defined (see UpdateCompletedType), but is likely to be the
+ // "right" answer.
+ ResultType = llvm::Type::getInt32Ty(getLLVMContext());
+ break;
}
case Type::BlockPointer: {
- const QualType FTy = cast<BlockPointerType>(Ty).getPointeeType();
- llvm::OpaqueType *PointeeType = llvm::OpaqueType::get(getLLVMContext());
- PointersToResolve.push_back(std::make_pair(FTy, PointeeType));
+ const QualType FTy = cast<BlockPointerType>(Ty)->getPointeeType();
+ llvm::Type *PointeeType = ConvertTypeForMem(FTy);
unsigned AS = Context.getTargetAddressSpace(FTy);
- return llvm::PointerType::get(PointeeType, AS);
+ ResultType = llvm::PointerType::get(PointeeType, AS);
+ break;
}
case Type::MemberPointer: {
- return getCXXABI().ConvertMemberPointerType(cast<MemberPointerType>(&Ty));
+ ResultType =
+ getCXXABI().ConvertMemberPointerType(cast<MemberPointerType>(Ty));
+ break;
}
}
-
- // FIXME: implement.
- return llvm::OpaqueType::get(getLLVMContext());
+
+ assert(ResultType && "Didn't convert a type?");
+
+ TypeCache[Ty] = ResultType;
+ return ResultType;
}
-/// ConvertTagDeclType - Lay out a tagged decl type like struct or union or
-/// enum.
-const llvm::Type *CodeGenTypes::ConvertTagDeclType(const TagDecl *TD) {
+/// ConvertRecordDeclType - Lay out a tagged decl type like struct or union.
+llvm::StructType *CodeGenTypes::ConvertRecordDeclType(const RecordDecl *RD) {
// TagDecl's are not necessarily unique, instead use the (clang)
// type connected to the decl.
- const Type *Key =
- Context.getTagDeclType(TD).getTypePtr();
- llvm::DenseMap<const Type*, llvm::PATypeHolder>::iterator TDTI =
- TagDeclTypes.find(Key);
-
- // If we've already compiled this tag type, use the previous definition.
- if (TDTI != TagDeclTypes.end())
- return TDTI->second;
-
- const EnumDecl *ED = dyn_cast<EnumDecl>(TD);
-
- // If this is still a forward declaration, just define an opaque
- // type to use for this tagged decl.
- // C++0x: If this is a enumeration type with fixed underlying type,
- // consider it complete.
- if (!TD->isDefinition() && !(ED && ED->isFixed())) {
- llvm::Type *ResultType = llvm::OpaqueType::get(getLLVMContext());
- TagDeclTypes.insert(std::make_pair(Key, ResultType));
- return ResultType;
- }
-
- // Okay, this is a definition of a type. Compile the implementation now.
-
- if (ED) // Don't bother storing enums in TagDeclTypes.
- return ConvertTypeRecursive(ED->getIntegerType());
+ const Type *Key = Context.getTagDeclType(RD).getTypePtr();
- // This decl could well be recursive. In this case, insert an opaque
- // definition of this type, which the recursive uses will get. We will then
- // refine this opaque version later.
+ llvm::StructType *&Entry = RecordDeclTypes[Key];
- // Create new OpaqueType now for later use in case this is a recursive
- // type. This will later be refined to the actual type.
- llvm::PATypeHolder ResultHolder = llvm::OpaqueType::get(getLLVMContext());
- TagDeclTypes.insert(std::make_pair(Key, ResultHolder));
+ // If we don't have a StructType at all yet, create the forward declaration.
+ if (Entry == 0) {
+ Entry = llvm::StructType::createNamed(getLLVMContext(), "");
+ addRecordTypeName(RD, Entry, "");
+ }
+ llvm::StructType *Ty = Entry;
- const RecordDecl *RD = cast<const RecordDecl>(TD);
+ // If this is still a forward declaration, or the LLVM type is already
+ // complete, there's nothing more to do.
+ RD = RD->getDefinition();
+ if (RD == 0 || !Ty->isOpaque())
+ return Ty;
+
+ // If converting this type would cause us to infinitely loop, don't do it!
+ if (!isSafeToConvert(RD, *this)) {
+ DeferredRecords.push_back(RD);
+ return Ty;
+ }
+ // Okay, this is a definition of a type. Compile the implementation now.
+ bool InsertResult = RecordsBeingLaidOut.insert(Key); (void)InsertResult;
+ assert(InsertResult && "Recursively compiling a struct?");
+
// Force conversion of non-virtual base classes recursively.
- if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(TD)) {
- for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end(); i != e; ++i) {
- if (!i->isVirtual()) {
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
- ConvertTagDeclType(Base);
- }
+ if (const CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) {
+ for (CXXRecordDecl::base_class_const_iterator i = CRD->bases_begin(),
+ e = CRD->bases_end(); i != e; ++i) {
+ if (i->isVirtual()) continue;
+
+ ConvertRecordDeclType(i->getType()->getAs<RecordType>()->getDecl());
}
}
// Layout fields.
- CGRecordLayout *Layout = ComputeRecordLayout(RD);
-
+ CGRecordLayout *Layout = ComputeRecordLayout(RD, Ty);
CGRecordLayouts[Key] = Layout;
- const llvm::Type *ResultType = Layout->getLLVMType();
- // Refine our Opaque type to ResultType. This can invalidate ResultType, so
- // make sure to read the result out of the holder.
- cast<llvm::OpaqueType>(ResultHolder.get())
- ->refineAbstractTypeTo(ResultType);
+ // We're done laying out this struct.
+ bool EraseResult = RecordsBeingLaidOut.erase(Key); (void)EraseResult;
+ assert(EraseResult && "struct not in RecordsBeingLaidOut set?");
+
+ // If this struct blocked a FunctionType conversion, then recompute whatever
+ // was derived from that.
+ // FIXME: This is hugely overconservative.
+ if (SkippedLayout)
+ TypeCache.clear();
+
+ // If we're done converting the outer-most record, then convert any deferred
+ // structs as well.
+ if (RecordsBeingLaidOut.empty())
+ while (!DeferredRecords.empty())
+ ConvertRecordDeclType(DeferredRecords.pop_back_val());
- return ResultHolder.get();
+ return Ty;
}
/// getCGRecordLayout - Return record layout info for the given record decl.
@@ -503,7 +621,7 @@ CodeGenTypes::getCGRecordLayout(const RecordDecl *RD) {
const CGRecordLayout *Layout = CGRecordLayouts.lookup(Key);
if (!Layout) {
// Compute the type information.
- ConvertTagDeclType(RD);
+ ConvertRecordDeclType(RD);
// Now try again.
Layout = CGRecordLayouts.lookup(Key);
@@ -513,15 +631,6 @@ CodeGenTypes::getCGRecordLayout(const RecordDecl *RD) {
return *Layout;
}
-void CodeGenTypes::addBaseSubobjectTypeName(const CXXRecordDecl *RD,
- const CGRecordLayout &layout) {
- llvm::StringRef suffix;
- if (layout.getBaseSubobjectLLVMType() != layout.getLLVMType())
- suffix = ".base";
-
- addRecordTypeName(RD, layout.getBaseSubobjectLLVMType(), suffix);
-}
-
bool CodeGenTypes::isZeroInitializable(QualType T) {
// No need to check for member pointers when not compiling C++.
if (!Context.getLangOptions().CPlusPlus)
diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h
index ff1eb4c45b59..7c0fb8164373 100644
--- a/lib/CodeGen/CodeGenTypes.h
+++ b/lib/CodeGen/CodeGenTypes.h
@@ -15,7 +15,7 @@
#define CLANG_CODEGEN_CODEGENTYPES_H
#include "CGCall.h"
-#include "GlobalDecl.h"
+#include "clang/AST/GlobalDecl.h"
#include "llvm/Module.h"
#include "llvm/ADT/DenseMap.h"
#include <vector>
@@ -23,11 +23,10 @@
namespace llvm {
class FunctionType;
class Module;
- class OpaqueType;
- class PATypeHolder;
class TargetData;
class Type;
class LLVMContext;
+ class StructType;
}
namespace clang {
@@ -37,6 +36,7 @@ namespace clang {
class CXXConstructorDecl;
class CXXDestructorDecl;
class CXXMethodDecl;
+ class CodeGenOptions;
class FieldDecl;
class FunctionProtoType;
class ObjCInterfaceDecl;
@@ -58,91 +58,83 @@ namespace CodeGen {
class CodeGenTypes {
ASTContext &Context;
const TargetInfo &Target;
- llvm::Module& TheModule;
- const llvm::TargetData& TheTargetData;
- const ABIInfo& TheABIInfo;
+ llvm::Module &TheModule;
+ const llvm::TargetData &TheTargetData;
+ const ABIInfo &TheABIInfo;
CGCXXABI &TheCXXABI;
-
- llvm::SmallVector<std::pair<QualType,
- llvm::OpaqueType *>, 8> PointersToResolve;
-
- llvm::DenseMap<const Type*, llvm::PATypeHolder> TagDeclTypes;
-
- llvm::DenseMap<const Type*, llvm::PATypeHolder> FunctionTypes;
+ const CodeGenOptions &CodeGenOpts;
/// The opaque type map for Objective-C interfaces. All direct
/// manipulation is done by the runtime interfaces, which are
/// responsible for coercing to the appropriate type; these opaque
/// types are never refined.
- llvm::DenseMap<const ObjCInterfaceType*, const llvm::Type *> InterfaceTypes;
+ llvm::DenseMap<const ObjCInterfaceType*, llvm::Type *> InterfaceTypes;
/// CGRecordLayouts - This maps llvm struct type with corresponding
/// record layout info.
llvm::DenseMap<const Type*, CGRecordLayout *> CGRecordLayouts;
+ /// RecordDeclTypes - This contains the LLVM IR type for any converted
+ /// RecordDecl.
+ llvm::DenseMap<const Type*, llvm::StructType *> RecordDeclTypes;
+
/// FunctionInfos - Hold memoized CGFunctionInfo results.
llvm::FoldingSet<CGFunctionInfo> FunctionInfos;
+ /// RecordsBeingLaidOut - This set keeps track of records that we're currently
+ /// converting to an IR type. For example, when converting:
+ /// struct A { struct B { int x; } } when processing 'x', the 'A' and 'B'
+ /// types will be in this set.
+ llvm::SmallPtrSet<const Type*, 4> RecordsBeingLaidOut;
+
+ llvm::SmallPtrSet<const CGFunctionInfo*, 4> FunctionsBeingProcessed;
+
+ /// SkippedLayout - True if we didn't layout a function due to a being inside
+ /// a recursive struct conversion, set this to true.
+ bool SkippedLayout;
+
+ llvm::SmallVector<const RecordDecl *, 8> DeferredRecords;
+
private:
- /// TypeCache - This map keeps cache of llvm::Types (through PATypeHolder)
- /// and maps llvm::Types to corresponding clang::Type. llvm::PATypeHolder is
- /// used instead of llvm::Type because it allows us to bypass potential
- /// dangling type pointers due to type refinement on llvm side.
- llvm::DenseMap<const Type *, llvm::PATypeHolder> TypeCache;
-
- /// ConvertNewType - Convert type T into a llvm::Type. Do not use this
- /// method directly because it does not do any type caching. This method
- /// is available only for ConvertType(). CovertType() is preferred
- /// interface to convert type T into a llvm::Type.
- const llvm::Type *ConvertNewType(QualType T);
-
- /// HandleLateResolvedPointers - For top-level ConvertType calls, this handles
- /// pointers that are referenced but have not been converted yet. This is
- /// used to handle cyclic structures properly.
- void HandleLateResolvedPointers();
-
- /// addRecordTypeName - Compute a name from the given record decl with an
- /// optional suffix and name the given LLVM type using it.
- void addRecordTypeName(const RecordDecl *RD, const llvm::Type *Ty,
- llvm::StringRef suffix);
+ /// TypeCache - This map keeps cache of llvm::Types
+ /// and maps llvm::Types to corresponding clang::Type.
+ llvm::DenseMap<const Type *, llvm::Type *> TypeCache;
public:
CodeGenTypes(ASTContext &Ctx, llvm::Module &M, const llvm::TargetData &TD,
- const ABIInfo &Info, CGCXXABI &CXXABI);
+ const ABIInfo &Info, CGCXXABI &CXXABI,
+ const CodeGenOptions &Opts);
~CodeGenTypes();
const llvm::TargetData &getTargetData() const { return TheTargetData; }
const TargetInfo &getTarget() const { return Target; }
ASTContext &getContext() const { return Context; }
const ABIInfo &getABIInfo() const { return TheABIInfo; }
+ const CodeGenOptions &getCodeGenOpts() const { return CodeGenOpts; }
CGCXXABI &getCXXABI() const { return TheCXXABI; }
llvm::LLVMContext &getLLVMContext() { return TheModule.getContext(); }
/// ConvertType - Convert type T into a llvm::Type.
- const llvm::Type *ConvertType(QualType T, bool IsRecursive = false);
- const llvm::Type *ConvertTypeRecursive(QualType T);
+ llvm::Type *ConvertType(QualType T);
/// ConvertTypeForMem - Convert type T into a llvm::Type. This differs from
/// ConvertType in that it is used to convert to the memory representation for
/// a type. For example, the scalar representation for _Bool is i1, but the
/// memory representation is usually i8 or i32, depending on the target.
- const llvm::Type *ConvertTypeForMem(QualType T, bool IsRecursive = false);
- const llvm::Type *ConvertTypeForMemRecursive(QualType T) {
- return ConvertTypeForMem(T, true);
- }
+ llvm::Type *ConvertTypeForMem(QualType T);
/// GetFunctionType - Get the LLVM function type for \arg Info.
- const llvm::FunctionType *GetFunctionType(const CGFunctionInfo &Info,
- bool IsVariadic,
- bool IsRecursive = false);
+ llvm::FunctionType *GetFunctionType(const CGFunctionInfo &Info,
+ bool IsVariadic);
- const llvm::FunctionType *GetFunctionType(GlobalDecl GD);
+ llvm::FunctionType *GetFunctionType(GlobalDecl GD);
- /// VerifyFuncTypeComplete - Utility to check whether a function type can
+ /// isFuncTypeConvertible - Utility to check whether a function type can
/// be converted to an LLVM type (i.e. doesn't depend on an incomplete tag
/// type).
- static const TagType *VerifyFuncTypeComplete(const Type* T);
-
+ bool isFuncTypeConvertible(const FunctionType *FT);
+ bool isFuncTypeArgumentConvertible(QualType Ty);
+
/// GetFunctionTypeForVTable - Get the LLVM function type for use in a vtable,
/// given a CXXMethodDecl. If the method to has an incomplete return type,
/// and/or incomplete argument types, this will return the opaque type.
@@ -150,11 +142,6 @@ public:
const CGRecordLayout &getCGRecordLayout(const RecordDecl*);
- /// addBaseSubobjectTypeName - Add a type name for the base subobject of the
- /// given record layout.
- void addBaseSubobjectTypeName(const CXXRecordDecl *RD,
- const CGRecordLayout &layout);
-
/// UpdateCompletedType - When we find the full definition for a TagDecl,
/// replace the 'opaque' type we previously made for it if applicable.
void UpdateCompletedType(const TagDecl *TD);
@@ -180,10 +167,8 @@ public:
Ty->getExtInfo());
}
- const CGFunctionInfo &getFunctionInfo(CanQual<FunctionProtoType> Ty,
- bool IsRecursive = false);
- const CGFunctionInfo &getFunctionInfo(CanQual<FunctionNoProtoType> Ty,
- bool IsRecursive = false);
+ const CGFunctionInfo &getFunctionInfo(CanQual<FunctionProtoType> Ty);
+ const CGFunctionInfo &getFunctionInfo(CanQual<FunctionNoProtoType> Ty);
/// getFunctionInfo - Get the function info for a member function of
/// the given type. This is used for calls through member function
@@ -206,23 +191,27 @@ public:
/// \param ArgTys - must all actually be canonical as params
const CGFunctionInfo &getFunctionInfo(CanQualType RetTy,
const llvm::SmallVectorImpl<CanQualType> &ArgTys,
- const FunctionType::ExtInfo &Info,
- bool IsRecursive = false);
+ const FunctionType::ExtInfo &Info);
/// \brief Compute a new LLVM record layout object for the given record.
- CGRecordLayout *ComputeRecordLayout(const RecordDecl *D);
+ CGRecordLayout *ComputeRecordLayout(const RecordDecl *D,
+ llvm::StructType *Ty);
+
+ /// addRecordTypeName - Compute a name from the given record decl with an
+ /// optional suffix and name the given LLVM type using it.
+ void addRecordTypeName(const RecordDecl *RD, llvm::StructType *Ty,
+ llvm::StringRef suffix);
+
public: // These are internal details of CGT that shouldn't be used externally.
- /// ConvertTagDeclType - Lay out a tagged decl type like struct or union or
- /// enum.
- const llvm::Type *ConvertTagDeclType(const TagDecl *TD);
+ /// ConvertRecordDeclType - Lay out a tagged decl type like struct or union.
+ llvm::StructType *ConvertRecordDeclType(const RecordDecl *TD);
/// GetExpandedTypes - Expand the type \arg Ty into the LLVM
/// argument types it would be passed as on the provided vector \arg
/// ArgTys. See ABIArgInfo::Expand.
void GetExpandedTypes(QualType type,
- llvm::SmallVectorImpl<const llvm::Type*> &expanded,
- bool isRecursive);
+ llvm::SmallVectorImpl<llvm::Type*> &expanded);
/// IsZeroInitializable - Return whether a type can be
/// zero-initialized (in the C++ sense) with an LLVM zeroinitializer.
@@ -231,6 +220,15 @@ public: // These are internal details of CGT that shouldn't be used externally.
/// IsZeroInitializable - Return whether a record type can be
/// zero-initialized (in the C++ sense) with an LLVM zeroinitializer.
bool isZeroInitializable(const CXXRecordDecl *RD);
+
+ bool isRecordLayoutComplete(const Type *Ty) const;
+ bool noRecordsBeingLaidOut() const {
+ return RecordsBeingLaidOut.empty();
+ }
+ bool isRecordBeingLaidOut(const Type *Ty) const {
+ return RecordsBeingLaidOut.count(Ty);
+ }
+
};
} // end namespace CodeGen
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp
index 12ef9bd030bd..0c86080fa80e 100644
--- a/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/lib/CodeGen/ItaniumCXXABI.cpp
@@ -24,6 +24,7 @@
#include "CodeGenModule.h"
#include <clang/AST/Mangle.h>
#include <clang/AST/Type.h>
+#include <llvm/Intrinsics.h>
#include <llvm/Target/TargetData.h>
#include <llvm/Value.h>
@@ -33,15 +34,15 @@ using namespace CodeGen;
namespace {
class ItaniumCXXABI : public CodeGen::CGCXXABI {
private:
- const llvm::IntegerType *PtrDiffTy;
+ llvm::IntegerType *PtrDiffTy;
protected:
bool IsARM;
// It's a little silly for us to cache this.
- const llvm::IntegerType *getPtrDiffTy() {
+ llvm::IntegerType *getPtrDiffTy() {
if (!PtrDiffTy) {
QualType T = getContext().getPointerDiffType();
- const llvm::Type *Ty = CGM.getTypes().ConvertTypeRecursive(T);
+ llvm::Type *Ty = CGM.getTypes().ConvertType(T);
PtrDiffTy = cast<llvm::IntegerType>(Ty);
}
return PtrDiffTy;
@@ -57,7 +58,7 @@ public:
bool isZeroInitializable(const MemberPointerType *MPT);
- const llvm::Type *ConvertMemberPointerType(const MemberPointerType *MPT);
+ llvm::Type *ConvertMemberPointerType(const MemberPointerType *MPT);
llvm::Value *EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
llvm::Value *&This,
@@ -175,13 +176,11 @@ CodeGen::CGCXXABI *CodeGen::CreateARMCXXABI(CodeGenModule &CGM) {
return new ARMCXXABI(CGM);
}
-const llvm::Type *
+llvm::Type *
ItaniumCXXABI::ConvertMemberPointerType(const MemberPointerType *MPT) {
if (MPT->isMemberDataPointer())
return getPtrDiffTy();
- else
- return llvm::StructType::get(CGM.getLLVMContext(),
- getPtrDiffTy(), getPtrDiffTy(), NULL);
+ return llvm::StructType::get(getPtrDiffTy(), getPtrDiffTy(), NULL);
}
/// In the Itanium and ARM ABIs, method pointers have the form:
@@ -473,8 +472,7 @@ ItaniumCXXABI::EmitMemberPointerConversion(llvm::Constant *C,
else
Values[1] = llvm::ConstantExpr::getAdd(CS->getOperand(1), Offset);
- return llvm::ConstantStruct::get(CGM.getLLVMContext(), Values, 2,
- /*Packed=*/false);
+ return llvm::ConstantStruct::get(CS->getType(), Values);
}
@@ -489,8 +487,7 @@ ItaniumCXXABI::EmitNullMemberPointer(const MemberPointerType *MPT) {
llvm::Constant *Zero = llvm::ConstantInt::get(ptrdiff_t, 0);
llvm::Constant *Values[2] = { Zero, Zero };
- return llvm::ConstantStruct::get(CGM.getLLVMContext(), Values, 2,
- /*Packed=*/false);
+ return llvm::ConstantStruct::getAnon(Values);
}
llvm::Constant *
@@ -540,7 +537,7 @@ llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) {
const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
const llvm::Type *Ty;
// Check whether the function has a computable LLVM signature.
- if (!CodeGenTypes::VerifyFuncTypeComplete(FPT)) {
+ if (Types.isFuncTypeConvertible(FPT)) {
// The function has a computable LLVM signature; use the correct type.
Ty = Types.GetFunctionType(Types.getFunctionInfo(MD),
FPT->isVariadic());
@@ -555,8 +552,7 @@ llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) {
MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, 0);
}
- return llvm::ConstantStruct::get(CGM.getLLVMContext(),
- MemPtr, 2, /*Packed=*/false);
+ return llvm::ConstantStruct::getAnon(MemPtr);
}
/// The comparison algorithm is pretty easy: the member pointers are
@@ -802,10 +798,27 @@ bool ItaniumCXXABI::NeedsArrayCookie(const CXXNewExpr *expr) {
if (expr->doesUsualArrayDeleteWantSize())
return true;
+ // Automatic Reference Counting:
+ // We need an array cookie for pointers with strong or weak lifetime.
+ QualType AllocatedType = expr->getAllocatedType();
+ if (getContext().getLangOptions().ObjCAutoRefCount &&
+ AllocatedType->isObjCLifetimeType()) {
+ switch (AllocatedType.getObjCLifetime()) {
+ case Qualifiers::OCL_None:
+ case Qualifiers::OCL_ExplicitNone:
+ case Qualifiers::OCL_Autoreleasing:
+ return false;
+
+ case Qualifiers::OCL_Strong:
+ case Qualifiers::OCL_Weak:
+ return true;
+ }
+ }
+
// Otherwise, if the class has a non-trivial destructor, it always
// needs a cookie.
const CXXRecordDecl *record =
- expr->getAllocatedType()->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
+ AllocatedType->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
return (record && !record->hasTrivialDestructor());
}
@@ -816,6 +829,22 @@ bool ItaniumCXXABI::NeedsArrayCookie(const CXXDeleteExpr *expr,
if (expr->doesUsualArrayDeleteWantSize())
return true;
+ // Automatic Reference Counting:
+ // We need an array cookie for pointers with strong or weak lifetime.
+ if (getContext().getLangOptions().ObjCAutoRefCount &&
+ elementType->isObjCLifetimeType()) {
+ switch (elementType.getObjCLifetime()) {
+ case Qualifiers::OCL_None:
+ case Qualifiers::OCL_ExplicitNone:
+ case Qualifiers::OCL_Autoreleasing:
+ return false;
+
+ case Qualifiers::OCL_Strong:
+ case Qualifiers::OCL_Weak:
+ return true;
+ }
+ }
+
// Otherwise, if the class has a non-trivial destructor, it always
// needs a cookie.
const CXXRecordDecl *record =
@@ -1005,31 +1034,34 @@ void ARMCXXABI::ReadArrayCookie(CodeGenFunction &CGF,
/*********************** Static local initialization **************************/
static llvm::Constant *getGuardAcquireFn(CodeGenModule &CGM,
- const llvm::PointerType *GuardPtrTy) {
+ llvm::PointerType *GuardPtrTy) {
// int __cxa_guard_acquire(__guard *guard_object);
+ llvm::Type *ArgTys[] = { GuardPtrTy };
const llvm::FunctionType *FTy =
llvm::FunctionType::get(CGM.getTypes().ConvertType(CGM.getContext().IntTy),
- GuardPtrTy, /*isVarArg=*/false);
+ ArgTys, /*isVarArg=*/false);
return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_acquire");
}
static llvm::Constant *getGuardReleaseFn(CodeGenModule &CGM,
- const llvm::PointerType *GuardPtrTy) {
+ llvm::PointerType *GuardPtrTy) {
// void __cxa_guard_release(__guard *guard_object);
+ llvm::Type *ArgTys[] = { GuardPtrTy };
const llvm::FunctionType *FTy =
llvm::FunctionType::get(llvm::Type::getVoidTy(CGM.getLLVMContext()),
- GuardPtrTy, /*isVarArg=*/false);
+ ArgTys, /*isVarArg=*/false);
return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_release");
}
static llvm::Constant *getGuardAbortFn(CodeGenModule &CGM,
- const llvm::PointerType *GuardPtrTy) {
+ llvm::PointerType *GuardPtrTy) {
// void __cxa_guard_abort(__guard *guard_object);
+ llvm::Type *ArgTys[] = { GuardPtrTy };
const llvm::FunctionType *FTy =
llvm::FunctionType::get(llvm::Type::getVoidTy(CGM.getLLVMContext()),
- GuardPtrTy, /*isVarArg=*/false);
+ ArgTys, /*isVarArg=*/false);
return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_abort");
}
@@ -1039,7 +1071,7 @@ namespace {
llvm::GlobalVariable *Guard;
CallGuardAbort(llvm::GlobalVariable *Guard) : Guard(Guard) {}
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
CGF.Builder.CreateCall(getGuardAbortFn(CGF.CGM, Guard->getType()), Guard)
->setDoesNotThrow();
}
@@ -1055,21 +1087,21 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
// We only need to use thread-safe statics for local variables;
// global initialization is always single-threaded.
- bool ThreadsafeStatics = (getContext().getLangOptions().ThreadsafeStatics &&
- D.isLocalVarDecl());
+ bool threadsafe =
+ (getContext().getLangOptions().ThreadsafeStatics && D.isLocalVarDecl());
const llvm::IntegerType *GuardTy;
// If we have a global variable with internal linkage and thread-safe statics
// are disabled, we can just let the guard variable be of type i8.
- bool UseInt8GuardVariable = !ThreadsafeStatics && GV->hasInternalLinkage();
- if (UseInt8GuardVariable)
- GuardTy = Builder.getInt8Ty();
- else {
+ bool useInt8GuardVariable = !threadsafe && GV->hasInternalLinkage();
+ if (useInt8GuardVariable) {
+ GuardTy = CGF.Int8Ty;
+ } else {
// Guard variables are 64 bits in the generic ABI and 32 bits on ARM.
- GuardTy = (IsARM ? Builder.getInt32Ty() : Builder.getInt64Ty());
+ GuardTy = (IsARM ? CGF.Int32Ty : CGF.Int64Ty);
}
- const llvm::PointerType *GuardPtrTy = GuardTy->getPointerTo();
+ llvm::PointerType *GuardPtrTy = GuardTy->getPointerTo();
// Create the guard variable.
llvm::SmallString<256> GuardVName;
@@ -1099,7 +1131,7 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
// if (__cxa_guard_acquire(&obj_guard))
// ...
// }
- if (IsARM && !UseInt8GuardVariable) {
+ if (IsARM && !useInt8GuardVariable) {
llvm::Value *V = Builder.CreateLoad(GuardVariable);
V = Builder.CreateAnd(V, Builder.getInt32(1));
IsInitialized = Builder.CreateIsNull(V, "guard.uninitialized");
@@ -1130,13 +1162,16 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
llvm::BasicBlock *InitCheckBlock = CGF.createBasicBlock("init.check");
llvm::BasicBlock *EndBlock = CGF.createBasicBlock("init.end");
+ llvm::BasicBlock *NoCheckBlock = EndBlock;
+ if (threadsafe) NoCheckBlock = CGF.createBasicBlock("init.barrier");
+
// Check if the first byte of the guard variable is zero.
- Builder.CreateCondBr(IsInitialized, InitCheckBlock, EndBlock);
+ Builder.CreateCondBr(IsInitialized, InitCheckBlock, NoCheckBlock);
CGF.EmitBlock(InitCheckBlock);
// Variables used when coping with thread-safe statics and exceptions.
- if (ThreadsafeStatics) {
+ if (threadsafe) {
// Call __cxa_guard_acquire.
llvm::Value *V
= Builder.CreateCall(getGuardAcquireFn(CGM, GuardPtrTy), GuardVariable);
@@ -1155,7 +1190,7 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
// Emit the initializer and add a global destructor if appropriate.
CGF.EmitCXXGlobalVarDeclInit(D, GV);
- if (ThreadsafeStatics) {
+ if (threadsafe) {
// Pop the guard-abort cleanup if we pushed one.
CGF.PopCleanupBlock();
@@ -1165,5 +1200,23 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
Builder.CreateStore(llvm::ConstantInt::get(GuardTy, 1), GuardVariable);
}
+ // Emit an acquire memory barrier if using thread-safe statics:
+ // Itanium ABI:
+ // An implementation supporting thread-safety on multiprocessor
+ // systems must also guarantee that references to the initialized
+ // object do not occur before the load of the initialization flag.
+ if (threadsafe) {
+ Builder.CreateBr(EndBlock);
+ CGF.EmitBlock(NoCheckBlock);
+
+ llvm::Value *_false = Builder.getFalse();
+ llvm::Value *_true = Builder.getTrue();
+
+ Builder.CreateCall5(CGM.getIntrinsic(llvm::Intrinsic::memory_barrier),
+ /* load-load, load-store */ _true, _true,
+ /* store-load, store-store */ _false, _false,
+ /* device or I/O */ _false);
+ }
+
CGF.EmitBlock(EndBlock);
}
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index 043ead7e62d9..df2c1bd98cca 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -75,7 +75,7 @@ void ABIArgInfo::dump() const {
break;
case Indirect:
OS << "Indirect Align=" << getIndirectAlign()
- << " Byal=" << getIndirectByVal()
+ << " ByVal=" << getIndirectByVal()
<< " Realign=" << getIndirectRealign();
break;
case Expand:
@@ -356,9 +356,9 @@ bool UseX86_MMXType(const llvm::Type *IRType) {
IRType->getScalarSizeInBits() != 64;
}
-static const llvm::Type* X86AdjustInlineAsmType(CodeGen::CodeGenFunction &CGF,
- llvm::StringRef Constraint,
- const llvm::Type* Ty) {
+static llvm::Type* X86AdjustInlineAsmType(CodeGen::CodeGenFunction &CGF,
+ llvm::StringRef Constraint,
+ llvm::Type* Ty) {
if ((Constraint == "y" || Constraint == "&y") && Ty->isVectorTy())
return llvm::Type::getX86_MMXTy(CGF.getLLVMContext());
return Ty;
@@ -374,6 +374,7 @@ class X86_32ABIInfo : public ABIInfo {
bool IsDarwinVectorABI;
bool IsSmallStructInRegABI;
+ bool IsMMXDisabled;
static bool isRegisterSize(unsigned Size) {
return (Size == 8 || Size == 16 || Size == 32 || Size == 64);
@@ -403,14 +404,15 @@ public:
virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
CodeGenFunction &CGF) const;
- X86_32ABIInfo(CodeGen::CodeGenTypes &CGT, bool d, bool p)
- : ABIInfo(CGT), IsDarwinVectorABI(d), IsSmallStructInRegABI(p) {}
+ X86_32ABIInfo(CodeGen::CodeGenTypes &CGT, bool d, bool p, bool m)
+ : ABIInfo(CGT), IsDarwinVectorABI(d), IsSmallStructInRegABI(p),
+ IsMMXDisabled(m) {}
};
class X86_32TargetCodeGenInfo : public TargetCodeGenInfo {
public:
- X86_32TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, bool d, bool p)
- :TargetCodeGenInfo(new X86_32ABIInfo(CGT, d, p)) {}
+ X86_32TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, bool d, bool p, bool m)
+ :TargetCodeGenInfo(new X86_32ABIInfo(CGT, d, p, m)) {}
void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
CodeGen::CodeGenModule &CGM) const;
@@ -425,9 +427,9 @@ public:
bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
llvm::Value *Address) const;
- const llvm::Type* adjustInlineAsmType(CodeGen::CodeGenFunction &CGF,
- llvm::StringRef Constraint,
- const llvm::Type* Ty) const {
+ llvm::Type* adjustInlineAsmType(CodeGen::CodeGenFunction &CGF,
+ llvm::StringRef Constraint,
+ llvm::Type* Ty) const {
return X86AdjustInlineAsmType(CGF, Constraint, Ty);
}
@@ -562,7 +564,7 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy) const {
} else if (SeltTy->isPointerType()) {
// FIXME: It would be really nice if this could come out as the proper
// pointer type.
- const llvm::Type *PtrTy = llvm::Type::getInt8PtrTy(getVMContext());
+ llvm::Type *PtrTy = llvm::Type::getInt8PtrTy(getVMContext());
return ABIArgInfo::getDirect(PtrTy);
} else if (SeltTy->isVectorType()) {
// 64- and 128-bit vectors are never returned in a
@@ -699,8 +701,11 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty) const {
Size));
}
- const llvm::Type *IRType = CGT.ConvertTypeRecursive(Ty);
+ llvm::Type *IRType = CGT.ConvertType(Ty);
if (UseX86_MMXType(IRType)) {
+ if (IsMMXDisabled)
+ return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(),
+ 64));
ABIArgInfo AAI = ABIArgInfo::getDirect(IRType);
AAI.setCoerceToType(llvm::Type::getX86_MMXTy(getVMContext()));
return AAI;
@@ -820,6 +825,22 @@ class X86_64ABIInfo : public ABIInfo {
/// should just return Memory for the aggregate).
static Class merge(Class Accum, Class Field);
+ /// postMerge - Implement the X86_64 ABI post merging algorithm.
+ ///
+ /// Post merger cleanup, reduces a malformed Hi and Lo pair to
+ /// final MEMORY or SSE classes when necessary.
+ ///
+ /// \param AggregateSize - The size of the current aggregate in
+ /// the classification process.
+ ///
+ /// \param Lo - The classification for the parts of the type
+ /// residing in the low word of the containing object.
+ ///
+ /// \param Hi - The classification for the parts of the type
+ /// residing in the higher words of the containing object.
+ ///
+ void postMerge(unsigned AggregateSize, Class &Lo, Class &Hi) const;
+
/// classify - Determine the x86_64 register classes in which the
/// given type T should be passed.
///
@@ -843,13 +864,13 @@ class X86_64ABIInfo : public ABIInfo {
/// also be ComplexX87.
void classify(QualType T, uint64_t OffsetBase, Class &Lo, Class &Hi) const;
- const llvm::Type *Get16ByteVectorType(QualType Ty) const;
- const llvm::Type *GetSSETypeAtOffset(const llvm::Type *IRType,
- unsigned IROffset, QualType SourceTy,
- unsigned SourceOffset) const;
- const llvm::Type *GetINTEGERTypeAtOffset(const llvm::Type *IRType,
- unsigned IROffset, QualType SourceTy,
- unsigned SourceOffset) const;
+ llvm::Type *GetByteVectorType(QualType Ty) const;
+ llvm::Type *GetSSETypeAtOffset(llvm::Type *IRType,
+ unsigned IROffset, QualType SourceTy,
+ unsigned SourceOffset) const;
+ llvm::Type *GetINTEGERTypeAtOffset(llvm::Type *IRType,
+ unsigned IROffset, QualType SourceTy,
+ unsigned SourceOffset) const;
/// getIndirectResult - Give a source type \arg Ty, return a suitable result
/// such that the argument will be returned in memory.
@@ -921,9 +942,9 @@ public:
return false;
}
- const llvm::Type* adjustInlineAsmType(CodeGen::CodeGenFunction &CGF,
- llvm::StringRef Constraint,
- const llvm::Type* Ty) const {
+ llvm::Type* adjustInlineAsmType(CodeGen::CodeGenFunction &CGF,
+ llvm::StringRef Constraint,
+ llvm::Type* Ty) const {
return X86AdjustInlineAsmType(CGF, Constraint, Ty);
}
@@ -956,6 +977,39 @@ public:
}
+void X86_64ABIInfo::postMerge(unsigned AggregateSize, Class &Lo,
+ Class &Hi) const {
+ // AMD64-ABI 3.2.3p2: Rule 5. Then a post merger cleanup is done:
+ //
+ // (a) If one of the classes is Memory, the whole argument is passed in
+ // memory.
+ //
+ // (b) If X87UP is not preceded by X87, the whole argument is passed in
+ // memory.
+ //
+ // (c) If the size of the aggregate exceeds two eightbytes and the first
+ // eightbyte isn't SSE or any other eightbyte isn't SSEUP, the whole
+ // argument is passed in memory. NOTE: This is necessary to keep the
+ // ABI working for processors that don't support the __m256 type.
+ //
+ // (d) If SSEUP is not preceded by SSE or SSEUP, it is converted to SSE.
+ //
+ // Some of these are enforced by the merging logic. Others can arise
+ // only with unions; for example:
+ // union { _Complex double; unsigned; }
+ //
+ // Note that clauses (b) and (c) were added in 0.98.
+ //
+ if (Hi == Memory)
+ Lo = Memory;
+ if (Hi == X87Up && Lo != X87 && honorsRevision0_98())
+ Lo = Memory;
+ if (AggregateSize > 128 && (Lo != SSE || Hi != SSEUp))
+ Lo = Memory;
+ if (Hi == SSEUp && Lo != SSE)
+ Hi = SSE;
+}
+
X86_64ABIInfo::Class X86_64ABIInfo::merge(Class Accum, Class Field) {
// AMD64-ABI 3.2.3p2: Rule 4. Each field of an object is
// classified recursively so that always two fields are
@@ -1082,7 +1136,14 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
// split.
if (OffsetBase && OffsetBase != 64)
Hi = Lo;
- } else if (Size == 128) {
+ } else if (Size == 128 || Size == 256) {
+ // Arguments of 256-bits are split into four eightbyte chunks. The
+ // least significant one belongs to class SSE and all the others to class
+ // SSEUP. The original Lo and Hi design considers that types can't be
+ // greater than 128-bits, so a 64-bit split in Hi and Lo makes sense.
+ // This design isn't correct for 256-bits, but since there're no cases
+ // where the upper parts would need to be inspected, avoid adding
+ // complexity and just consider Hi to match the 64-256 part.
Lo = SSE;
Hi = SSEUp;
}
@@ -1121,8 +1182,8 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
uint64_t Size = getContext().getTypeSize(Ty);
// AMD64-ABI 3.2.3p2: Rule 1. If the size of an object is larger
- // than two eightbytes, ..., it has class MEMORY.
- if (Size > 128)
+ // than four eightbytes, ..., it has class MEMORY.
+ if (Size > 256)
return;
// AMD64-ABI 3.2.3p2: Rule 1. If ..., or it contains unaligned
@@ -1137,6 +1198,13 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
Current = NoClass;
uint64_t EltSize = getContext().getTypeSize(AT->getElementType());
uint64_t ArraySize = AT->getSize().getZExtValue();
+
+ // The only case a 256-bit wide vector could be used is when the array
+ // contains a single 256-bit element. Since Lo and Hi logic isn't extended
+ // to work for sizes wider than 128, early check and fallback to memory.
+ if (Size > 128 && EltSize != 256)
+ return;
+
for (uint64_t i=0, Offset=OffsetBase; i<ArraySize; ++i, Offset += EltSize) {
Class FieldLo, FieldHi;
classify(AT->getElementType(), Offset, FieldLo, FieldHi);
@@ -1146,9 +1214,7 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
break;
}
- // Do post merger cleanup (see below). Only case we worry about is Memory.
- if (Hi == Memory)
- Lo = Memory;
+ postMerge(Size, Lo, Hi);
assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp array classification.");
return;
}
@@ -1157,8 +1223,8 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
uint64_t Size = getContext().getTypeSize(Ty);
// AMD64-ABI 3.2.3p2: Rule 1. If the size of an object is larger
- // than two eightbytes, ..., it has class MEMORY.
- if (Size > 128)
+ // than four eightbytes, ..., it has class MEMORY.
+ if (Size > 256)
return;
// AMD64-ABI 3.2.3p2: Rule 2. If a C++ object has either a non-trivial
@@ -1209,9 +1275,17 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
uint64_t Offset = OffsetBase + Layout.getFieldOffset(idx);
bool BitField = i->isBitField();
- // AMD64-ABI 3.2.3p2: Rule 1. If ..., or it contains unaligned
- // fields, it has class MEMORY.
+ // AMD64-ABI 3.2.3p2: Rule 1. If the size of an object is larger than
+ // four eightbytes, or it contains unaligned fields, it has class MEMORY.
+ //
+ // The only case a 256-bit wide vector could be used is when the struct
+ // contains a single 256-bit element. Since Lo and Hi logic isn't extended
+ // to work for sizes wider than 128, early check and fallback to memory.
//
+ if (Size > 128 && getContext().getTypeSize(i->getType()) != 256) {
+ Lo = Memory;
+ return;
+ }
// Note, skip this test for bit-fields, see below.
if (!BitField && Offset % getContext().getTypeAlign(i->getType())) {
Lo = Memory;
@@ -1257,31 +1331,7 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
break;
}
- // AMD64-ABI 3.2.3p2: Rule 5. Then a post merger cleanup is done:
- //
- // (a) If one of the classes is MEMORY, the whole argument is
- // passed in memory.
- //
- // (b) If X87UP is not preceded by X87, the whole argument is
- // passed in memory.
- //
- // (c) If the size of the aggregate exceeds two eightbytes and the first
- // eight-byte isn’t SSE or any other eightbyte isn’t SSEUP, the whole
- // argument is passed in memory.
- //
- // (d) If SSEUP is not preceded by SSE or SSEUP, it is converted to SSE.
- //
- // Some of these are enforced by the merging logic. Others can arise
- // only with unions; for example:
- // union { _Complex double; unsigned; }
- //
- // Note that clauses (b) and (c) were added in 0.98.
- if (Hi == Memory)
- Lo = Memory;
- if (Hi == X87Up && Lo != X87 && honorsRevision0_98())
- Lo = Memory;
- if (Hi == SSEUp && Lo != SSE)
- Hi = SSE;
+ postMerge(Size, Lo, Hi);
}
}
@@ -1321,24 +1371,25 @@ ABIArgInfo X86_64ABIInfo::getIndirectResult(QualType Ty) const {
return ABIArgInfo::getIndirect(Align);
}
-/// Get16ByteVectorType - The ABI specifies that a value should be passed in an
-/// full vector XMM register. Pick an LLVM IR type that will be passed as a
+/// GetByteVectorType - The ABI specifies that a value should be passed in an
+/// full vector XMM/YMM register. Pick an LLVM IR type that will be passed as a
/// vector register.
-const llvm::Type *X86_64ABIInfo::Get16ByteVectorType(QualType Ty) const {
- const llvm::Type *IRType = CGT.ConvertTypeRecursive(Ty);
+llvm::Type *X86_64ABIInfo::GetByteVectorType(QualType Ty) const {
+ llvm::Type *IRType = CGT.ConvertType(Ty);
// Wrapper structs that just contain vectors are passed just like vectors,
// strip them off if present.
- const llvm::StructType *STy = dyn_cast<llvm::StructType>(IRType);
+ llvm::StructType *STy = dyn_cast<llvm::StructType>(IRType);
while (STy && STy->getNumElements() == 1) {
IRType = STy->getElementType(0);
STy = dyn_cast<llvm::StructType>(IRType);
}
// If the preferred type is a 16-byte vector, prefer to pass it.
- if (const llvm::VectorType *VT = dyn_cast<llvm::VectorType>(IRType)){
- const llvm::Type *EltTy = VT->getElementType();
- if (VT->getBitWidth() == 128 &&
+ if (llvm::VectorType *VT = dyn_cast<llvm::VectorType>(IRType)){
+ llvm::Type *EltTy = VT->getElementType();
+ unsigned BitWidth = VT->getBitWidth();
+ if ((BitWidth == 128 || BitWidth == 256) &&
(EltTy->isFloatTy() || EltTy->isDoubleTy() ||
EltTy->isIntegerTy(8) || EltTy->isIntegerTy(16) ||
EltTy->isIntegerTy(32) || EltTy->isIntegerTy(64) ||
@@ -1466,8 +1517,8 @@ static bool ContainsFloatAtOffset(const llvm::Type *IRType, unsigned IROffset,
/// GetSSETypeAtOffset - Return a type that will be passed by the backend in the
/// low 8 bytes of an XMM register, corresponding to the SSE class.
-const llvm::Type *X86_64ABIInfo::
-GetSSETypeAtOffset(const llvm::Type *IRType, unsigned IROffset,
+llvm::Type *X86_64ABIInfo::
+GetSSETypeAtOffset(llvm::Type *IRType, unsigned IROffset,
QualType SourceTy, unsigned SourceOffset) const {
// The only three choices we have are either double, <2 x float>, or float. We
// pass as float if the last 4 bytes is just padding. This happens for
@@ -1501,8 +1552,8 @@ GetSSETypeAtOffset(const llvm::Type *IRType, unsigned IROffset,
/// SourceTy is the source level type for the entire argument. SourceOffset is
/// an offset into this that we're processing (which is always either 0 or 8).
///
-const llvm::Type *X86_64ABIInfo::
-GetINTEGERTypeAtOffset(const llvm::Type *IRType, unsigned IROffset,
+llvm::Type *X86_64ABIInfo::
+GetINTEGERTypeAtOffset(llvm::Type *IRType, unsigned IROffset,
QualType SourceTy, unsigned SourceOffset) const {
// If we're dealing with an un-offset LLVM IR type, then it means that we're
// returning an 8-byte unit starting with it. See if we can safely use it.
@@ -1540,7 +1591,7 @@ GetINTEGERTypeAtOffset(const llvm::Type *IRType, unsigned IROffset,
}
if (const llvm::ArrayType *ATy = dyn_cast<llvm::ArrayType>(IRType)) {
- const llvm::Type *EltTy = ATy->getElementType();
+ llvm::Type *EltTy = ATy->getElementType();
unsigned EltSize = getTargetData().getTypeAllocSize(EltTy);
unsigned EltOffset = IROffset/EltSize*EltSize;
return GetINTEGERTypeAtOffset(EltTy, IROffset-EltOffset, SourceTy,
@@ -1566,8 +1617,8 @@ GetINTEGERTypeAtOffset(const llvm::Type *IRType, unsigned IROffset,
/// first class aggregate to represent them. For example, if the low part of
/// a by-value argument should be passed as i32* and the high part as float,
/// return {i32*, float}.
-static const llvm::Type *
-GetX86_64ByValArgumentPair(const llvm::Type *Lo, const llvm::Type *Hi,
+static llvm::Type *
+GetX86_64ByValArgumentPair(llvm::Type *Lo, llvm::Type *Hi,
const llvm::TargetData &TD) {
// In order to correctly satisfy the ABI, we need to the high part to start
// at offset 8. If the high and low parts we inferred are both 4-byte types
@@ -1594,8 +1645,7 @@ GetX86_64ByValArgumentPair(const llvm::Type *Lo, const llvm::Type *Hi,
}
}
- const llvm::StructType *Result =
- llvm::StructType::get(Lo->getContext(), Lo, Hi, NULL);
+ llvm::StructType *Result = llvm::StructType::get(Lo, Hi, NULL);
// Verify that the second element is at an 8-byte offset.
@@ -1615,7 +1665,7 @@ classifyReturnType(QualType RetTy) const {
assert((Hi != Memory || Lo == Memory) && "Invalid memory classification.");
assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp classification.");
- const llvm::Type *ResType = 0;
+ llvm::Type *ResType = 0;
switch (Lo) {
case NoClass:
if (Hi == NoClass)
@@ -1638,8 +1688,7 @@ classifyReturnType(QualType RetTy) const {
// AMD64-ABI 3.2.3p4: Rule 3. If the class is INTEGER, the next
// available register of the sequence %rax, %rdx is used.
case Integer:
- ResType = GetINTEGERTypeAtOffset(CGT.ConvertTypeRecursive(RetTy), 0,
- RetTy, 0);
+ ResType = GetINTEGERTypeAtOffset(CGT.ConvertType(RetTy), 0, RetTy, 0);
// If we have a sign or zero extended integer, make sure to return Extend
// so that the parameter gets the right LLVM IR attributes.
@@ -1657,7 +1706,7 @@ classifyReturnType(QualType RetTy) const {
// AMD64-ABI 3.2.3p4: Rule 4. If the class is SSE, the next
// available SSE register of the sequence %xmm0, %xmm1 is used.
case SSE:
- ResType = GetSSETypeAtOffset(CGT.ConvertTypeRecursive(RetTy), 0, RetTy, 0);
+ ResType = GetSSETypeAtOffset(CGT.ConvertType(RetTy), 0, RetTy, 0);
break;
// AMD64-ABI 3.2.3p4: Rule 6. If the class is X87, the value is
@@ -1671,14 +1720,13 @@ classifyReturnType(QualType RetTy) const {
// %st1.
case ComplexX87:
assert(Hi == ComplexX87 && "Unexpected ComplexX87 classification.");
- ResType = llvm::StructType::get(getVMContext(),
- llvm::Type::getX86_FP80Ty(getVMContext()),
+ ResType = llvm::StructType::get(llvm::Type::getX86_FP80Ty(getVMContext()),
llvm::Type::getX86_FP80Ty(getVMContext()),
NULL);
break;
}
- const llvm::Type *HighPart = 0;
+ llvm::Type *HighPart = 0;
switch (Hi) {
// Memory was handled previously and X87 should
// never occur as a hi class.
@@ -1691,24 +1739,24 @@ classifyReturnType(QualType RetTy) const {
break;
case Integer:
- HighPart = GetINTEGERTypeAtOffset(CGT.ConvertTypeRecursive(RetTy),
- 8, RetTy, 8);
+ HighPart = GetINTEGERTypeAtOffset(CGT.ConvertType(RetTy), 8, RetTy, 8);
if (Lo == NoClass) // Return HighPart at offset 8 in memory.
return ABIArgInfo::getDirect(HighPart, 8);
break;
case SSE:
- HighPart = GetSSETypeAtOffset(CGT.ConvertTypeRecursive(RetTy), 8, RetTy, 8);
+ HighPart = GetSSETypeAtOffset(CGT.ConvertType(RetTy), 8, RetTy, 8);
if (Lo == NoClass) // Return HighPart at offset 8 in memory.
return ABIArgInfo::getDirect(HighPart, 8);
break;
// AMD64-ABI 3.2.3p4: Rule 5. If the class is SSEUP, the eightbyte
- // is passed in the upper half of the last used SSE register.
+ // is passed in the next available eightbyte chunk if the last used
+ // vector register.
//
// SSEUP should always be preceded by SSE, just widen.
case SSEUp:
assert(Lo == SSE && "Unexpected SSEUp classification.");
- ResType = Get16ByteVectorType(RetTy);
+ ResType = GetByteVectorType(RetTy);
break;
// AMD64-ABI 3.2.3p4: Rule 7. If the class is X87UP, the value is
@@ -1719,8 +1767,7 @@ classifyReturnType(QualType RetTy) const {
// preceded by X87. In such situations we follow gcc and pass the
// extra bits in an SSE reg.
if (Lo != X87) {
- HighPart = GetSSETypeAtOffset(CGT.ConvertTypeRecursive(RetTy),
- 8, RetTy, 8);
+ HighPart = GetSSETypeAtOffset(CGT.ConvertType(RetTy), 8, RetTy, 8);
if (Lo == NoClass) // Return HighPart at offset 8 in memory.
return ABIArgInfo::getDirect(HighPart, 8);
}
@@ -1748,7 +1795,7 @@ ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, unsigned &neededInt,
neededInt = 0;
neededSSE = 0;
- const llvm::Type *ResType = 0;
+ llvm::Type *ResType = 0;
switch (Lo) {
case NoClass:
if (Hi == NoClass)
@@ -1767,6 +1814,8 @@ ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, unsigned &neededInt,
// COMPLEX_X87, it is passed in memory.
case X87:
case ComplexX87:
+ if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty))
+ ++neededInt;
return getIndirectResult(Ty);
case SSEUp:
@@ -1780,7 +1829,7 @@ ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, unsigned &neededInt,
++neededInt;
// Pick an 8-byte type based on the preferred type.
- ResType = GetINTEGERTypeAtOffset(CGT.ConvertTypeRecursive(Ty), 0, Ty, 0);
+ ResType = GetINTEGERTypeAtOffset(CGT.ConvertType(Ty), 0, Ty, 0);
// If we have a sign or zero extended integer, make sure to return Extend
// so that the parameter gets the right LLVM IR attributes.
@@ -1800,19 +1849,14 @@ ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, unsigned &neededInt,
// available SSE register is used, the registers are taken in the
// order from %xmm0 to %xmm7.
case SSE: {
- const llvm::Type *IRType = CGT.ConvertTypeRecursive(Ty);
- if (Hi != NoClass || !UseX86_MMXType(IRType))
- ResType = GetSSETypeAtOffset(IRType, 0, Ty, 0);
- else
- // This is an MMX type. Treat it as such.
- ResType = llvm::Type::getX86_MMXTy(getVMContext());
-
+ llvm::Type *IRType = CGT.ConvertType(Ty);
+ ResType = GetSSETypeAtOffset(IRType, 0, Ty, 0);
++neededSSE;
break;
}
}
- const llvm::Type *HighPart = 0;
+ llvm::Type *HighPart = 0;
switch (Hi) {
// Memory was handled previously, ComplexX87 and X87 should
// never occur as hi classes, and X87Up must be preceded by X87,
@@ -1828,7 +1872,7 @@ ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, unsigned &neededInt,
case Integer:
++neededInt;
// Pick an 8-byte type based on the preferred type.
- HighPart = GetINTEGERTypeAtOffset(CGT.ConvertTypeRecursive(Ty), 8, Ty, 8);
+ HighPart = GetINTEGERTypeAtOffset(CGT.ConvertType(Ty), 8, Ty, 8);
if (Lo == NoClass) // Pass HighPart at offset 8 in memory.
return ABIArgInfo::getDirect(HighPart, 8);
@@ -1838,7 +1882,7 @@ ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, unsigned &neededInt,
// memory), except in situations involving unions.
case X87Up:
case SSE:
- HighPart = GetSSETypeAtOffset(CGT.ConvertTypeRecursive(Ty), 8, Ty, 8);
+ HighPart = GetSSETypeAtOffset(CGT.ConvertType(Ty), 8, Ty, 8);
if (Lo == NoClass) // Pass HighPart at offset 8 in memory.
return ABIArgInfo::getDirect(HighPart, 8);
@@ -1851,7 +1895,7 @@ ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, unsigned &neededInt,
// register. This only happens when 128-bit vectors are passed.
case SSEUp:
assert(Lo == SSE && "Unexpected SSEUp classification");
- ResType = Get16ByteVectorType(Ty);
+ ResType = GetByteVectorType(Ty);
break;
}
@@ -2059,10 +2103,10 @@ llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
// area, we need to collect the two eightbytes together.
llvm::Value *RegAddrLo = CGF.Builder.CreateGEP(RegAddr, fp_offset);
llvm::Value *RegAddrHi = CGF.Builder.CreateConstGEP1_32(RegAddrLo, 16);
- const llvm::Type *DoubleTy = llvm::Type::getDoubleTy(VMContext);
+ llvm::Type *DoubleTy = llvm::Type::getDoubleTy(VMContext);
const llvm::Type *DblPtrTy =
llvm::PointerType::getUnqual(DoubleTy);
- const llvm::StructType *ST = llvm::StructType::get(VMContext, DoubleTy,
+ const llvm::StructType *ST = llvm::StructType::get(DoubleTy,
DoubleTy, NULL);
llvm::Value *V, *Tmp = CGF.CreateTempAlloca(ST);
V = CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegAddrLo,
@@ -2277,6 +2321,10 @@ public:
return 13;
}
+ llvm::StringRef getARCRetainAutoreleasedReturnValueMarker() const {
+ return "mov\tr7, r7\t\t@ marker for objc_retainAutoreleaseReturnValue";
+ }
+
bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
llvm::Value *Address) const {
CodeGen::CGBuilderTy &Builder = CGF.Builder;
@@ -2290,8 +2338,6 @@ public:
return false;
}
-
-
};
}
@@ -2371,9 +2417,8 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty) const {
SizeRegs = (getContext().getTypeSize(Ty) + 63) / 64;
}
- const llvm::Type *STy =
- llvm::StructType::get(getVMContext(),
- llvm::ArrayType::get(ElemTy, SizeRegs), NULL, NULL);
+ llvm::Type *STy =
+ llvm::StructType::get(llvm::ArrayType::get(ElemTy, SizeRegs), NULL);
return ABIArgInfo::getDirect(STy);
}
@@ -3010,10 +3055,12 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
case llvm::Triple::msp430:
return *(TheTargetCodeGenInfo = new MSP430TargetCodeGenInfo(Types));
- case llvm::Triple::x86:
+ case llvm::Triple::x86: {
+ bool DisableMMX = strcmp(getContext().Target.getABI(), "no-mmx") == 0;
+
if (Triple.isOSDarwin())
return *(TheTargetCodeGenInfo =
- new X86_32TargetCodeGenInfo(Types, true, true));
+ new X86_32TargetCodeGenInfo(Types, true, true, DisableMMX));
switch (Triple.getOS()) {
case llvm::Triple::Cygwin:
@@ -3024,12 +3071,13 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
case llvm::Triple::OpenBSD:
case llvm::Triple::NetBSD:
return *(TheTargetCodeGenInfo =
- new X86_32TargetCodeGenInfo(Types, false, true));
+ new X86_32TargetCodeGenInfo(Types, false, true, DisableMMX));
default:
return *(TheTargetCodeGenInfo =
- new X86_32TargetCodeGenInfo(Types, false, false));
+ new X86_32TargetCodeGenInfo(Types, false, false, DisableMMX));
}
+ }
case llvm::Triple::x86_64:
switch (Triple.getOS()) {
diff --git a/lib/CodeGen/TargetInfo.h b/lib/CodeGen/TargetInfo.h
index 4f59eb619e9d..d5e8884cdffe 100644
--- a/lib/CodeGen/TargetInfo.h
+++ b/lib/CodeGen/TargetInfo.h
@@ -106,11 +106,25 @@ namespace clang {
return Address;
}
- virtual const llvm::Type* adjustInlineAsmType(CodeGen::CodeGenFunction &CGF,
- llvm::StringRef Constraint,
- const llvm::Type* Ty) const {
+ virtual llvm::Type* adjustInlineAsmType(CodeGen::CodeGenFunction &CGF,
+ llvm::StringRef Constraint,
+ llvm::Type* Ty) const {
return Ty;
}
+
+ /// Retrieve the address of a function to call immediately before
+ /// calling objc_retainAutoreleasedReturnValue. The
+ /// implementation of objc_autoreleaseReturnValue sniffs the
+ /// instruction stream following its return address to decide
+ /// whether it's a call to objc_retainAutoreleasedReturnValue.
+ /// This can be prohibitively expensive, depending on the
+ /// relocation model, and so on some targets it instead sniffs for
+ /// a particular instruction sequence. This functions returns
+ /// that instruction sequence in inline assembly, which will be
+ /// empty if none is required.
+ virtual llvm::StringRef getARCRetainAutoreleasedReturnValueMarker() const {
+ return "";
+ }
};
}
diff --git a/lib/Driver/Arg.cpp b/lib/Driver/Arg.cpp
index f1177cf97e28..39b7e5556494 100644
--- a/lib/Driver/Arg.cpp
+++ b/lib/Driver/Arg.cpp
@@ -113,7 +113,7 @@ void Arg::render(const ArgList &Args, ArgStringList &Output) const {
break;
case Option::RenderSeparateStyle:
- Output.push_back(getOption().getName());
+ Output.push_back(getOption().getName().data());
for (unsigned i = 0, e = getNumValues(); i != e; ++i)
Output.push_back(getValue(Args, i));
break;
diff --git a/lib/Driver/ArgList.cpp b/lib/Driver/ArgList.cpp
index 596e2a7529cb..b8af9cc47e09 100644
--- a/lib/Driver/ArgList.cpp
+++ b/lib/Driver/ArgList.cpp
@@ -287,9 +287,9 @@ Arg *DerivedArgList::MakeSeparateArg(const Arg *BaseArg, const Option *Opt,
Arg *DerivedArgList::MakeJoinedArg(const Arg *BaseArg, const Option *Opt,
llvm::StringRef Value) const {
- unsigned Index = BaseArgs.MakeIndex(Opt->getName() + Value.str());
+ unsigned Index = BaseArgs.MakeIndex(Opt->getName().str() + Value.str());
Arg *A = new Arg(Opt, Index,
- BaseArgs.getArgString(Index) + strlen(Opt->getName()),
+ BaseArgs.getArgString(Index) + Opt->getName().size(),
BaseArg);
SynthesizedArgs.push_back(A);
return A;
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index eb878a3f1c5e..789f6f7ae9ce 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -458,11 +458,20 @@ bool Driver::HandleImmediateArgs(const Compilation &C) {
}
llvm::outs() << "\n";
llvm::outs() << "libraries: =";
+
+ std::string sysroot;
+ if (Arg *A = C.getArgs().getLastArg(options::OPT__sysroot_EQ))
+ sysroot = A->getValue(C.getArgs());
+
for (ToolChain::path_list::const_iterator it = TC.getFilePaths().begin(),
ie = TC.getFilePaths().end(); it != ie; ++it) {
if (it != TC.getFilePaths().begin())
llvm::outs() << ':';
- llvm::outs() << *it;
+ const char *path = it->c_str();
+ if (path[0] == '=')
+ llvm::outs() << sysroot << path + 1;
+ else
+ llvm::outs() << path;
}
llvm::outs() << "\n";
return false;
@@ -942,10 +951,6 @@ Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase,
case phases::Precompile:
return new PrecompileJobAction(Input, types::TY_PCH);
case phases::Compile: {
- bool HasO4 = false;
- if (const Arg *A = Args.getLastArg(options::OPT_O_Group))
- HasO4 = A->getOption().matches(options::OPT_O4);
-
if (Args.hasArg(options::OPT_fsyntax_only)) {
return new CompileJobAction(Input, types::TY_Nothing);
} else if (Args.hasArg(options::OPT_rewrite_objc)) {
@@ -954,9 +959,7 @@ Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase,
return new AnalyzeJobAction(Input, types::TY_Plist);
} else if (Args.hasArg(options::OPT_emit_ast)) {
return new CompileJobAction(Input, types::TY_AST);
- } else if (Args.hasArg(options::OPT_emit_llvm) ||
- Args.hasFlag(options::OPT_flto, options::OPT_fno_lto, false) ||
- HasO4) {
+ } else if (IsUsingLTO(Args)) {
types::ID Output =
Args.hasArg(options::OPT_S) ? types::TY_LTO_IR : types::TY_LTO_BC;
return new CompileJobAction(Input, Output);
@@ -972,6 +975,19 @@ Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase,
return 0;
}
+bool Driver::IsUsingLTO(const ArgList &Args) const {
+ // Check for -emit-llvm or -flto.
+ if (Args.hasArg(options::OPT_emit_llvm) ||
+ Args.hasFlag(options::OPT_flto, options::OPT_fno_lto, false))
+ return true;
+
+ // Check for -O4.
+ if (const Arg *A = Args.getLastArg(options::OPT_O_Group))
+ return A->getOption().matches(options::OPT_O4);
+
+ return false;
+}
+
void Driver::BuildJobs(Compilation &C) const {
llvm::PrettyStackTraceString CrashInfo("Building compilation jobs");
@@ -1245,6 +1261,15 @@ const char *Driver::GetNamedOutputPath(Compilation &C,
NamedOutput = C.getArgs().MakeArgString(Suffixed.c_str());
}
+ // If we're saving temps and the temp filename conflicts with the input
+ // filename, then avoid overwriting input file.
+ if (!AtTopLevel && C.getArgs().hasArg(options::OPT_save_temps) &&
+ NamedOutput == BaseName) {
+ std::string TmpName =
+ GetTemporaryPath(types::getTypeTempSuffix(JA.getType()));
+ return C.addTempFile(C.getArgs().MakeArgString(TmpName.c_str()));
+ }
+
// As an annoying special case, PCH generation doesn't strip the pathname.
if (JA.getType() == types::TY_PCH) {
llvm::sys::path::remove_filename(BasePath);
diff --git a/lib/Driver/Option.cpp b/lib/Driver/Option.cpp
index a992cef3d239..90d21a3d0b17 100644
--- a/lib/Driver/Option.cpp
+++ b/lib/Driver/Option.cpp
@@ -144,7 +144,7 @@ FlagOption::FlagOption(OptSpecifier ID, const char *Name,
Arg *FlagOption::accept(const ArgList &Args, unsigned &Index) const {
// Matches iff this is an exact match.
// FIXME: Avoid strlen.
- if (strlen(getName()) != strlen(Args.getArgString(Index)))
+ if (getName().size() != strlen(Args.getArgString(Index)))
return 0;
return new Arg(getUnaliasedOption(), Index++);
@@ -157,7 +157,7 @@ JoinedOption::JoinedOption(OptSpecifier ID, const char *Name,
Arg *JoinedOption::accept(const ArgList &Args, unsigned &Index) const {
// Always matches.
- const char *Value = Args.getArgString(Index) + strlen(getName());
+ const char *Value = Args.getArgString(Index) + getName().size();
return new Arg(getUnaliasedOption(), Index++, Value);
}
@@ -170,7 +170,7 @@ CommaJoinedOption::CommaJoinedOption(OptSpecifier ID, const char *Name,
Arg *CommaJoinedOption::accept(const ArgList &Args,
unsigned &Index) const {
// Always matches.
- const char *Str = Args.getArgString(Index) + strlen(getName());
+ const char *Str = Args.getArgString(Index) + getName().size();
Arg *A = new Arg(getUnaliasedOption(), Index++);
// Parse out the comma separated values.
@@ -205,7 +205,7 @@ SeparateOption::SeparateOption(OptSpecifier ID, const char *Name,
Arg *SeparateOption::accept(const ArgList &Args, unsigned &Index) const {
// Matches iff this is an exact match.
// FIXME: Avoid strlen.
- if (strlen(getName()) != strlen(Args.getArgString(Index)))
+ if (getName().size() != strlen(Args.getArgString(Index)))
return 0;
Index += 2;
@@ -225,7 +225,7 @@ MultiArgOption::MultiArgOption(OptSpecifier ID, const char *Name,
Arg *MultiArgOption::accept(const ArgList &Args, unsigned &Index) const {
// Matches iff this is an exact match.
// FIXME: Avoid strlen.
- if (strlen(getName()) != strlen(Args.getArgString(Index)))
+ if (getName().size() != strlen(Args.getArgString(Index)))
return 0;
Index += 1 + NumArgs;
@@ -250,8 +250,8 @@ Arg *JoinedOrSeparateOption::accept(const ArgList &Args,
unsigned &Index) const {
// If this is not an exact match, it is a joined arg.
// FIXME: Avoid strlen.
- if (strlen(getName()) != strlen(Args.getArgString(Index))) {
- const char *Value = Args.getArgString(Index) + strlen(getName());
+ if (getName().size() != strlen(Args.getArgString(Index))) {
+ const char *Value = Args.getArgString(Index) + getName().size();
return new Arg(this, Index++, Value);
}
@@ -279,6 +279,6 @@ Arg *JoinedAndSeparateOption::accept(const ArgList &Args,
return 0;
return new Arg(getUnaliasedOption(), Index - 2,
- Args.getArgString(Index-2)+strlen(getName()),
+ Args.getArgString(Index-2)+getName().size(),
Args.getArgString(Index-1));
}
diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp
index d9199154104a..74b65918f34f 100644
--- a/lib/Driver/ToolChain.cpp
+++ b/lib/Driver/ToolChain.cpp
@@ -15,7 +15,9 @@
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/HostInfo.h"
+#include "clang/Driver/ObjCRuntime.h"
#include "clang/Driver/Options.h"
+#include "llvm/Support/ErrorHandling.h"
using namespace clang::driver;
@@ -47,6 +49,25 @@ bool ToolChain::HasNativeLLVMSupport() const {
return false;
}
+void ToolChain::configureObjCRuntime(ObjCRuntime &runtime) const {
+ switch (runtime.getKind()) {
+ case ObjCRuntime::NeXT:
+ // Assume a minimal NeXT runtime.
+ runtime.HasARC = false;
+ runtime.HasWeak = false;
+ runtime.HasTerminate = false;
+ return;
+
+ case ObjCRuntime::GNU:
+ // Assume a maximal GNU runtime.
+ runtime.HasARC = true;
+ runtime.HasWeak = true;
+ runtime.HasTerminate = false; // to be added
+ return;
+ }
+ llvm_unreachable("invalid runtime kind!");
+}
+
/// getARMTargetCPU - Get the (LLVM) name of the ARM cpu we are targeting.
//
// FIXME: tblgen this.
@@ -201,18 +222,21 @@ ToolChain::CXXStdlibType ToolChain::GetCXXStdlibType(const ArgList &Args) const{
}
void ToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const {
+ ArgStringList &CmdArgs,
+ bool ObjCXXAutoRefCount) const {
CXXStdlibType Type = GetCXXStdlibType(Args);
+ // Header search paths are handled by the mass of goop in InitHeaderSearch.
+
switch (Type) {
case ToolChain::CST_Libcxx:
- CmdArgs.push_back("-nostdinc++");
- CmdArgs.push_back("-cxx-isystem");
- CmdArgs.push_back("/usr/include/c++/v1");
+ if (ObjCXXAutoRefCount)
+ CmdArgs.push_back("-fobjc-arc-cxxlib=libc++");
break;
case ToolChain::CST_Libstdcxx:
- // Currently handled by the mass of goop in InitHeaderSearch.
+ if (ObjCXXAutoRefCount)
+ CmdArgs.push_back("-fobjc-arc-cxxlib=libstdc++");
break;
}
}
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index ca613e3d6c84..1619ef8f84a9 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -19,6 +19,7 @@
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/HostInfo.h"
+#include "clang/Driver/ObjCRuntime.h"
#include "clang/Driver/OptTable.h"
#include "clang/Driver/Option.h"
#include "clang/Driver/Options.h"
@@ -26,6 +27,7 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -35,13 +37,16 @@
#include <cstdlib> // ::getenv
+#include "llvm/Config/config.h" // for CXX_INCLUDE_ROOT
+
using namespace clang::driver;
using namespace clang::driver::toolchains;
/// Darwin - Darwin tool chain for i386 and x86_64.
Darwin::Darwin(const HostInfo &Host, const llvm::Triple& Triple)
- : ToolChain(Host, Triple), TargetInitialized(false)
+ : ToolChain(Host, Triple), TargetInitialized(false),
+ ARCRuntimeForSimulator(ARCSimulator_None)
{
// Compute the initial Darwin version based on the host.
bool HadExtra;
@@ -70,6 +75,39 @@ bool Darwin::HasNativeLLVMSupport() const {
return true;
}
+bool Darwin::hasARCRuntime() const {
+ // FIXME: Remove this once there is a proper way to detect an ARC runtime
+ // for the simulator.
+ switch (ARCRuntimeForSimulator) {
+ case ARCSimulator_None:
+ break;
+ case ARCSimulator_HasARCRuntime:
+ return true;
+ case ARCSimulator_NoARCRuntime:
+ return false;
+ }
+
+ if (isTargetIPhoneOS())
+ return !isIPhoneOSVersionLT(5);
+ else
+ return !isMacosxVersionLT(10, 7);
+}
+
+/// Darwin provides an ARC runtime starting in MacOS X 10.7 and iOS 5.0.
+void Darwin::configureObjCRuntime(ObjCRuntime &runtime) const {
+ if (runtime.getKind() != ObjCRuntime::NeXT)
+ return ToolChain::configureObjCRuntime(runtime);
+
+ runtime.HasARC = runtime.HasWeak = hasARCRuntime();
+
+ // So far, objc_terminate is only available in iOS 5.
+ // FIXME: do the simulator logic properly.
+ if (!ARCRuntimeForSimulator && isTargetIPhoneOS())
+ runtime.HasTerminate = !isIPhoneOSVersionLT(5);
+ else
+ runtime.HasTerminate = false;
+}
+
// FIXME: Can we tablegen this?
static const char *GetArmArchForMArch(llvm::StringRef Value) {
if (Value == "armv6k")
@@ -320,6 +358,45 @@ void DarwinClang::AddLinkSearchPathArgs(const ArgList &Args,
CmdArgs.push_back(Args.MakeArgString("-L" + P.str()));
}
+void DarwinClang::AddLinkARCArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+
+ CmdArgs.push_back("-force_load");
+ llvm::sys::Path P(getDriver().ClangExecutable);
+ P.eraseComponent(); // 'clang'
+ P.eraseComponent(); // 'bin'
+ P.appendComponent("lib");
+ P.appendComponent("arc");
+ P.appendComponent("libarclite_");
+ std::string s = P.str();
+ // Mash in the platform.
+ if (isTargetIPhoneOS())
+ s += "iphoneos";
+ // FIXME: isTargetIphoneOSSimulator() is not returning true.
+ else if (ARCRuntimeForSimulator != ARCSimulator_None)
+ s += "iphonesimulator";
+ else
+ s += "macosx";
+ s += ".a";
+
+ CmdArgs.push_back(Args.MakeArgString(s));
+}
+
+void DarwinClang::AddLinkRuntimeLib(const ArgList &Args,
+ ArgStringList &CmdArgs,
+ const char *DarwinStaticLib) const {
+ llvm::sys::Path P(getDriver().ResourceDir);
+ P.appendComponent("lib");
+ P.appendComponent("darwin");
+ P.appendComponent(DarwinStaticLib);
+
+ // For now, allow missing resource libraries to support developers who may
+ // not have compiler-rt checked out or integrated into their build.
+ bool Exists;
+ if (!llvm::sys::fs::exists(P.str(), Exists) && Exists)
+ CmdArgs.push_back(Args.MakeArgString(P.str()));
+}
+
void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
// Darwin doesn't support real static executables, don't link any runtime
@@ -341,7 +418,6 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
CmdArgs.push_back("-lSystem");
// Select the dynamic runtime library and the target specific static library.
- const char *DarwinStaticLib = 0;
if (isTargetIPhoneOS()) {
// If we are compiling as iOS / simulator, don't attempt to link libgcc_s.1,
// it never went into the SDK.
@@ -349,7 +425,7 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
CmdArgs.push_back("-lgcc_s.1");
// We currently always need a static runtime library for iOS.
- DarwinStaticLib = "libclang_rt.ios.a";
+ AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.ios.a");
} else {
// The dynamic runtime library was merged with libSystem for 10.6 and
// beyond; only 10.4 and 10.5 need an additional runtime library.
@@ -367,26 +443,42 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
// libSystem. Therefore, we still must provide a runtime library just for
// the tiny tiny handful of projects that *might* use that symbol.
if (isMacosxVersionLT(10, 5)) {
- DarwinStaticLib = "libclang_rt.10.4.a";
+ AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.10.4.a");
} else {
if (getTriple().getArch() == llvm::Triple::x86)
- DarwinStaticLib = "libclang_rt.eprintf.a";
+ AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.eprintf.a");
+ AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.osx.a");
}
}
+}
- /// Add the target specific static library, if needed.
- if (DarwinStaticLib) {
- llvm::sys::Path P(getDriver().ResourceDir);
- P.appendComponent("lib");
- P.appendComponent("darwin");
- P.appendComponent(DarwinStaticLib);
-
- // For now, allow missing resource libraries to support developers who may
- // not have compiler-rt checked out or integrated into their build.
- bool Exists;
- if (!llvm::sys::fs::exists(P.str(), Exists) && Exists)
- CmdArgs.push_back(Args.MakeArgString(P.str()));
- }
+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;
}
void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
@@ -396,6 +488,27 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
Arg *iOSVersion = Args.getLastArg(options::OPT_miphoneos_version_min_EQ);
Arg *iOSSimVersion = Args.getLastArg(
options::OPT_mios_simulator_version_min_EQ);
+
+ // FIXME: HACK! When compiling for the simulator we don't get a
+ // '-miphoneos-version-min' to help us know whether there is an ARC runtime
+ // or not; try to parse a __IPHONE_OS_VERSION_MIN_REQUIRED
+ // define passed in command-line.
+ if (!iOSVersion) {
+ for (arg_iterator it = Args.filtered_begin(options::OPT_D),
+ ie = Args.filtered_end(); it != ie; ++it) {
+ llvm::StringRef define = (*it)->getValue(Args);
+ if (define.startswith(SimulatorVersionDefineName())) {
+ unsigned Major, Minor, Micro;
+ if (GetVersionFromSimulatorDefine(define, Major, Minor, Micro) &&
+ Major < 10 && Minor < 100 && Micro < 100) {
+ ARCRuntimeForSimulator = Major < 5 ? ARCSimulator_NoARCRuntime
+ : ARCSimulator_HasARCRuntime;
+ }
+ break;
+ }
+ }
+ }
+
if (OSXVersion && (iOSVersion || iOSSimVersion)) {
getDriver().Diag(clang::diag::err_drv_argument_not_allowed_with)
<< OSXVersion->getAsString(Args)
@@ -587,8 +700,13 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
Arg *A = *it;
if (A->getOption().matches(options::OPT_Xarch__)) {
+ // Skip this argument unless the architecture matches either the toolchain
+ // triple arch, or the arch being bound.
+ //
// FIXME: Canonicalize name.
- if (getArchName() != A->getValue(Args, 0))
+ llvm::StringRef XarchArch = A->getValue(Args, 0);
+ if (!(XarchArch == getArchName() ||
+ (BoundArch && XarchArch == BoundArch)))
continue;
Arg *OriginalArg = A;
@@ -1359,7 +1477,7 @@ static std::string findGCCBaseLibDir(const std::string &GccTriple) {
ret.append(Version);
return ret;
}
- static const char* GccVersions[] = {"4.6.0", "4.6",
+ static const char* GccVersions[] = {"4.6.1", "4.6.0", "4.6",
"4.5.2", "4.5.1", "4.5",
"4.4.5", "4.4.4", "4.4.3", "4.4",
"4.3.4", "4.3.3", "4.3.2", "4.3",
@@ -1421,6 +1539,9 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple)
else if (!llvm::sys::fs::exists("/usr/lib/gcc/x86_64-pc-linux-gnu",
Exists) && Exists)
GccTriple = "x86_64-pc-linux-gnu";
+ else if (!llvm::sys::fs::exists("/usr/lib/gcc/x86_64-redhat-linux6E",
+ Exists) && Exists)
+ GccTriple = "x86_64-redhat-linux6E";
else if (!llvm::sys::fs::exists("/usr/lib/gcc/x86_64-redhat-linux",
Exists) && Exists)
GccTriple = "x86_64-redhat-linux";
diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h
index ace9b847919f..d68016b3a240 100644
--- a/lib/Driver/ToolChains.h
+++ b/lib/Driver/ToolChains.h
@@ -57,6 +57,16 @@ private:
// the argument translation business.
mutable bool TargetInitialized;
+ // FIXME: Remove this once there is a proper way to detect an ARC runtime
+ // for the simulator.
+ public:
+ mutable enum {
+ ARCSimulator_None,
+ ARCSimulator_HasARCRuntime,
+ ARCSimulator_NoARCRuntime
+ } ARCRuntimeForSimulator;
+
+private:
/// Whether we are targeting iPhoneOS target.
mutable bool TargetIsIPhoneOS;
@@ -70,6 +80,8 @@ private:
/// initialized.
std::string MacosxVersionMin;
+ bool hasARCRuntime() const;
+
private:
void AddDeploymentTarget(DerivedArgList &Args) const;
@@ -157,11 +169,15 @@ public:
virtual void AddLinkSearchPathArgs(const ArgList &Args,
ArgStringList &CmdArgs) const = 0;
+ /// AddLinkARCArgs - Add the linker arguments to link the ARC runtime library.
+ virtual void AddLinkARCArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const = 0;
+
/// AddLinkRuntimeLibArgs - Add the linker arguments to link the compiler
/// runtime library.
virtual void AddLinkRuntimeLibArgs(const ArgList &Args,
ArgStringList &CmdArgs) const = 0;
-
+
/// }
/// @name ToolChain Implementation
/// {
@@ -170,6 +186,8 @@ public:
virtual bool HasNativeLLVMSupport() const;
+ virtual void configureObjCRuntime(ObjCRuntime &runtime) const;
+
virtual DerivedArgList *TranslateArgs(const DerivedArgList &Args,
const char *BoundArch) const;
@@ -250,13 +268,17 @@ public:
virtual void AddLinkRuntimeLibArgs(const ArgList &Args,
ArgStringList &CmdArgs) const;
-
+ void AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs,
+ const char *DarwinStaticLib) const;
+
virtual void AddCXXStdlibLibArgs(const ArgList &Args,
ArgStringList &CmdArgs) const;
virtual void AddCCKextLibArgs(const ArgList &Args,
ArgStringList &CmdArgs) const;
+ virtual void AddLinkARCArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const;
/// }
};
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 8cd7adc42e84..eb17609d6c34 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -17,6 +17,7 @@
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Job.h"
#include "clang/Driver/HostInfo.h"
+#include "clang/Driver/ObjCRuntime.h"
#include "clang/Driver/Option.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/ToolChain.h"
@@ -30,6 +31,7 @@
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/Process.h"
+#include "llvm/Support/ErrorHandling.h"
#include "InputInfo.h"
#include "ToolChains.h"
@@ -147,20 +149,37 @@ static void AddLinkerInputs(const ToolChain &TC,
}
}
+/// \brief Determine whether Objective-C automated reference counting is
+/// enabled.
+static bool isObjCAutoRefCount(const ArgList &Args) {
+ return Args.hasFlag(options::OPT_fobjc_arc, options::OPT_fno_objc_arc, false);
+}
+
static void addProfileRT(const ToolChain &TC, const ArgList &Args,
- ArgStringList &CmdArgs) {
- if (Args.hasArg(options::OPT_fprofile_arcs) ||
- Args.hasArg(options::OPT_fprofile_generate) ||
- Args.hasArg(options::OPT_fcreate_profile) ||
- Args.hasArg(options::OPT_coverage)) {
- // GCC links libgcov.a by adding -L<inst>/gcc/lib/gcc/<triple>/<ver> -lgcov
- // to the link line. We cannot do the same thing because unlike gcov
- // there is a libprofile_rt.so. We used to use the -l:libprofile_rt.a
- // syntax, but that is not supported by old linkers.
- const char *lib = Args.MakeArgString(TC.getDriver().Dir + "/../lib/" +
- "libprofile_rt.a");
- CmdArgs.push_back(lib);
+ ArgStringList &CmdArgs,
+ llvm::Triple Triple) {
+ if (!(Args.hasArg(options::OPT_fprofile_arcs) ||
+ Args.hasArg(options::OPT_fprofile_generate) ||
+ Args.hasArg(options::OPT_fcreate_profile) ||
+ Args.hasArg(options::OPT_coverage)))
+ return;
+
+ // GCC links libgcov.a by adding -L<inst>/gcc/lib/gcc/<triple>/<ver> -lgcov to
+ // the link line. We cannot do the same thing because unlike gcov there is a
+ // libprofile_rt.so. We used to use the -l:libprofile_rt.a syntax, but that is
+ // not supported by old linkers.
+ llvm::Twine ProfileRT =
+ llvm::Twine(TC.getDriver().Dir) + "/../lib/" + "libprofile_rt.a";
+
+ if (Triple.getOS() == llvm::Triple::Darwin) {
+ // On Darwin, if the static library doesn't exist try the dylib.
+ bool Exists;
+ if (llvm::sys::fs::exists(ProfileRT.str(), Exists) || !Exists)
+ ProfileRT =
+ llvm::Twine(TC.getDriver().Dir) + "/../lib/" + "libprofile_rt.dylib";
}
+
+ CmdArgs.push_back(Args.MakeArgString(ProfileRT));
}
void Clang::AddPreprocessingOptions(const Driver &D,
@@ -223,6 +242,13 @@ void Clang::AddPreprocessingOptions(const Driver &D,
CmdArgs.push_back("-sys-header-deps");
}
+ if (Args.hasArg(options::OPT_MG)) {
+ if (!A || A->getOption().matches(options::OPT_MD) ||
+ A->getOption().matches(options::OPT_MMD))
+ D.Diag(clang::diag::err_drv_mg_requires_m_or_mm);
+ CmdArgs.push_back("-MG");
+ }
+
Args.AddLastArg(CmdArgs, options::OPT_MP);
// Convert all -MQ <target> args to -MT <quoted target>
@@ -318,8 +344,13 @@ void Clang::AddPreprocessingOptions(const Driver &D,
// Add C++ include arguments, if needed.
types::ID InputType = Inputs[0].getType();
- if (types::isCXX(InputType))
- getToolChain().AddClangCXXStdlibIncludeArgs(Args, CmdArgs);
+ if (types::isCXX(InputType)) {
+ bool ObjCXXAutoRefCount
+ = types::isObjC(InputType) && isObjCAutoRefCount(Args);
+ getToolChain().AddClangCXXStdlibIncludeArgs(Args, CmdArgs,
+ ObjCXXAutoRefCount);
+ Args.AddAllArgs(CmdArgs, options::OPT_stdlib_EQ);
+ }
// Add -Wp, and -Xassembler if using the preprocessor.
@@ -737,7 +768,6 @@ void Clang::AddSparcTargetArgs(const ArgList &Args,
//
// FIXME: This changes CPP defines, we need -target-soft-float.
CmdArgs.push_back("-msoft-float");
- CmdArgs.push_back("soft");
CmdArgs.push_back("-target-feature");
CmdArgs.push_back("+soft-float");
} else {
@@ -816,6 +846,14 @@ void Clang::AddX86TargetArgs(const ArgList &Args,
CmdArgs.push_back(CPUName);
}
+ // The required algorithm here is slightly strange: the options are applied
+ // in order (so -mno-sse -msse2 disables SSE3), but any option that gets
+ // directly overridden later is ignored (so "-mno-sse -msse2 -mno-sse2 -msse"
+ // is equivalent to "-mno-sse2 -msse"). The -cc1 handling deals with the
+ // former correctly, but not the latter; handle directly-overridden
+ // attributes here.
+ llvm::StringMap<unsigned> PrevFeature;
+ std::vector<const char*> Features;
for (arg_iterator it = Args.filtered_begin(options::OPT_m_x86_Features_Group),
ie = Args.filtered_end(); it != ie; ++it) {
llvm::StringRef Name = (*it)->getOption().getName();
@@ -829,25 +867,34 @@ void Clang::AddX86TargetArgs(const ArgList &Args,
if (IsNegative)
Name = Name.substr(3);
- CmdArgs.push_back("-target-feature");
- CmdArgs.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name));
+ unsigned& Prev = PrevFeature[Name];
+ if (Prev)
+ Features[Prev - 1] = 0;
+ Prev = Features.size() + 1;
+ Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name));
+ }
+ for (unsigned i = 0; i < Features.size(); i++) {
+ if (Features[i]) {
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back(Features[i]);
+ }
}
}
static bool
-shouldUseExceptionTablesForObjCExceptions(const ArgList &Args,
+shouldUseExceptionTablesForObjCExceptions(unsigned objcABIVersion,
const llvm::Triple &Triple) {
// We use the zero-cost exception tables for Objective-C if the non-fragile
// ABI is enabled or when compiling for x86_64 and ARM on Snow Leopard and
// later.
- if (Args.hasArg(options::OPT_fobjc_nonfragile_abi))
+ if (objcABIVersion >= 2)
return true;
if (Triple.getOS() != llvm::Triple::Darwin)
return false;
- return (Triple.getDarwinMajorNumber() >= 9 &&
+ return (!Triple.isMacOSXVersionLT(10,5) &&
(Triple.getArch() == llvm::Triple::x86_64 ||
Triple.getArch() == llvm::Triple::arm));
}
@@ -860,6 +907,7 @@ shouldUseExceptionTablesForObjCExceptions(const ArgList &Args,
static void addExceptionArgs(const ArgList &Args, types::ID InputType,
const llvm::Triple &Triple,
bool KernelOrKext, bool IsRewriter,
+ unsigned objcABIVersion,
ArgStringList &CmdArgs) {
if (KernelOrKext)
return;
@@ -896,7 +944,7 @@ static void addExceptionArgs(const ArgList &Args, types::ID InputType,
CmdArgs.push_back("-fobjc-exceptions");
ShouldUseExceptionTables |=
- shouldUseExceptionTablesForObjCExceptions(Args, Triple);
+ shouldUseExceptionTablesForObjCExceptions(objcABIVersion, Triple);
}
if (types::isCXX(InputType)) {
@@ -1040,6 +1088,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
} else if (Value == "--fatal-warnings") {
CmdArgs.push_back("-mllvm");
CmdArgs.push_back("-fatal-assembler-warnings");
+ } else if (Value == "--noexecstack") {
+ CmdArgs.push_back("-mnoexecstack");
} else {
D.Diag(clang::diag::err_drv_unsupported_option_argument)
<< A->getOption().getName() << Value;
@@ -1311,8 +1361,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
types::ID InputType = Inputs[0].getType();
if (!Args.hasArg(options::OPT_fallow_unsupported)) {
Arg *Unsupported;
- if ((Unsupported = Args.getLastArg(options::OPT_MG)) ||
- (Unsupported = Args.getLastArg(options::OPT_iframework)))
+ if ((Unsupported = Args.getLastArg(options::OPT_iframework)))
D.Diag(clang::diag::err_drv_clang_unsupported)
<< Unsupported->getOption().getName();
@@ -1378,6 +1427,28 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_working_directory);
+ if (!Args.hasArg(options::OPT_fno_objc_arc)) {
+ if (const Arg *A = Args.getLastArg(options::OPT_ccc_arcmt_check,
+ options::OPT_ccc_arcmt_modify,
+ options::OPT_ccc_arcmt_migrate)) {
+ switch (A->getOption().getID()) {
+ default:
+ llvm_unreachable("missed a case");
+ case options::OPT_ccc_arcmt_check:
+ CmdArgs.push_back("-arcmt-check");
+ break;
+ case options::OPT_ccc_arcmt_modify:
+ CmdArgs.push_back("-arcmt-modify");
+ break;
+ case options::OPT_ccc_arcmt_migrate:
+ CmdArgs.push_back("-arcmt-migrate");
+ CmdArgs.push_back("-arcmt-migrate-directory");
+ CmdArgs.push_back(A->getValue(Args));
+ break;
+ }
+ }
+ }
+
// Add preprocessing options like -I, -D, etc. if we are using the
// preprocessor.
//
@@ -1542,27 +1613,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_lax_vector_conversions))
CmdArgs.push_back("-fno-lax-vector-conversions");
- // -fobjc-infer-related-result-type is the default.
- if (Args.hasFlag(options::OPT_fobjc_infer_related_result_type,
- options::OPT_fno_objc_infer_related_result_type,
- /*Default=*/true))
- CmdArgs.push_back("-fobjc-infer-related-result-type");
-
- // Handle -fobjc-gc and -fobjc-gc-only. They are exclusive, and -fobjc-gc-only
- // takes precedence.
- const Arg *GCArg = Args.getLastArg(options::OPT_fobjc_gc_only);
- if (!GCArg)
- GCArg = Args.getLastArg(options::OPT_fobjc_gc);
- if (GCArg) {
- if (getToolChain().SupportsObjCGC()) {
- GCArg->render(Args, CmdArgs);
- } else {
- // FIXME: We should move this to a hard error.
- D.Diag(clang::diag::warn_drv_objc_gc_unsupported)
- << GCArg->getAsString(Args);
- }
- }
-
if (Args.getLastArg(options::OPT_fapple_kext))
CmdArgs.push_back("-fapple-kext");
@@ -1660,13 +1710,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
false))
CmdArgs.push_back("-fno-elide-constructors");
- // Add exception args.
- addExceptionArgs(Args, InputType, getToolChain().getTriple(),
- KernelOrKext, IsRewriter, CmdArgs);
-
- if (getToolChain().UseSjLjExceptions())
- CmdArgs.push_back("-fsjlj-exceptions");
-
// -frtti is default.
if (KernelOrKext ||
!Args.hasFlag(options::OPT_frtti, options::OPT_fno_rtti))
@@ -1734,30 +1777,41 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
false))
CmdArgs.push_back("-fgnu89-inline");
- // -fnext-runtime defaults to on Darwin and when rewriting Objective-C, and is
- // -the -cc1 default.
- bool NeXTRuntimeIsDefault =
- IsRewriter || getToolChain().getTriple().getOS() == llvm::Triple::Darwin;
- if (!Args.hasFlag(options::OPT_fnext_runtime, options::OPT_fgnu_runtime,
- NeXTRuntimeIsDefault))
- CmdArgs.push_back("-fgnu-runtime");
-
// -fobjc-nonfragile-abi=0 is default.
+ ObjCRuntime objCRuntime;
+ unsigned objcABIVersion = 0;
if (types::isObjC(InputType)) {
+ bool NeXTRuntimeIsDefault
+ = (IsRewriter || getToolChain().getTriple().isOSDarwin());
+ if (Args.hasFlag(options::OPT_fnext_runtime, options::OPT_fgnu_runtime,
+ NeXTRuntimeIsDefault)) {
+ objCRuntime.setKind(ObjCRuntime::NeXT);
+ } else {
+ CmdArgs.push_back("-fgnu-runtime");
+ objCRuntime.setKind(ObjCRuntime::GNU);
+ }
+ getToolChain().configureObjCRuntime(objCRuntime);
+ if (objCRuntime.HasARC)
+ CmdArgs.push_back("-fobjc-runtime-has-arc");
+ if (objCRuntime.HasWeak)
+ CmdArgs.push_back("-fobjc-runtime-has-weak");
+ if (objCRuntime.HasTerminate)
+ CmdArgs.push_back("-fobjc-runtime-has-terminate");
+
// Compute the Objective-C ABI "version" to use. Version numbers are
// slightly confusing for historical reasons:
// 1 - Traditional "fragile" ABI
// 2 - Non-fragile ABI, version 1
// 3 - Non-fragile ABI, version 2
- unsigned Version = 1;
+ objcABIVersion = 1;
// If -fobjc-abi-version= is present, use that to set the version.
if (Arg *A = Args.getLastArg(options::OPT_fobjc_abi_version_EQ)) {
if (llvm::StringRef(A->getValue(Args)) == "1")
- Version = 1;
+ objcABIVersion = 1;
else if (llvm::StringRef(A->getValue(Args)) == "2")
- Version = 2;
+ objcABIVersion = 2;
else if (llvm::StringRef(A->getValue(Args)) == "3")
- Version = 3;
+ objcABIVersion = 3;
else
D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
} else {
@@ -1783,13 +1837,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
<< A->getAsString(Args);
}
- Version = 1 + NonFragileABIVersion;
+ objcABIVersion = 1 + NonFragileABIVersion;
} else {
- Version = 1;
+ objcABIVersion = 1;
}
}
- if (Version == 2 || Version == 3) {
+ if (objcABIVersion == 2 || objcABIVersion == 3) {
CmdArgs.push_back("-fobjc-nonfragile-abi");
// -fobjc-dispatch-method is only relevant with the nonfragile-abi, and
@@ -1818,6 +1872,51 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
#endif
}
+ // Allow -fno-objc-arr to trump -fobjc-arr/-fobjc-arc.
+ // NOTE: This logic is duplicated in ToolChains.cpp.
+ bool ARC = isObjCAutoRefCount(Args);
+ if (ARC) {
+ CmdArgs.push_back("-fobjc-arc");
+
+ // Allow the user to enable full exceptions code emission.
+ // We define off for Objective-CC, on for Objective-C++.
+ if (Args.hasFlag(options::OPT_fobjc_arc_exceptions,
+ options::OPT_fno_objc_arc_exceptions,
+ /*default*/ types::isCXX(InputType)))
+ CmdArgs.push_back("-fobjc-arc-exceptions");
+ }
+
+ // -fobjc-infer-related-result-type is the default, except in the Objective-C
+ // rewriter.
+ if (IsRewriter)
+ CmdArgs.push_back("-fno-objc-infer-related-result-type");
+
+ // Handle -fobjc-gc and -fobjc-gc-only. They are exclusive, and -fobjc-gc-only
+ // takes precedence.
+ const Arg *GCArg = Args.getLastArg(options::OPT_fobjc_gc_only);
+ if (!GCArg)
+ GCArg = Args.getLastArg(options::OPT_fobjc_gc);
+ if (GCArg) {
+ if (ARC) {
+ D.Diag(clang::diag::err_drv_objc_gc_arr)
+ << GCArg->getAsString(Args);
+ } else if (getToolChain().SupportsObjCGC()) {
+ GCArg->render(Args, CmdArgs);
+ } else {
+ // FIXME: We should move this to a hard error.
+ D.Diag(clang::diag::warn_drv_objc_gc_unsupported)
+ << GCArg->getAsString(Args);
+ }
+ }
+
+ // Add exception args.
+ addExceptionArgs(Args, InputType, getToolChain().getTriple(),
+ KernelOrKext, IsRewriter, objcABIVersion, CmdArgs);
+
+ if (getToolChain().UseSjLjExceptions())
+ CmdArgs.push_back("-fsjlj-exceptions");
+
+ // C++ "sane" operator new.
if (!Args.hasFlag(options::OPT_fassume_sane_operator_new,
options::OPT_fno_assume_sane_operator_new))
CmdArgs.push_back("-fno-assume-sane-operator-new");
@@ -2858,6 +2957,17 @@ void darwin::Link::AddLinkArgs(Compilation &C,
CmdArgs.push_back("-demangle");
}
+ // If we are using LTO, then automatically create a temporary file path for
+ // the linker to use, so that it's lifetime will extend past a possible
+ // dsymutil step.
+ if (Version[0] >= 116 && D.IsUsingLTO(Args)) {
+ const char *TmpPath = C.getArgs().MakeArgString(
+ D.GetTemporaryPath(types::getTypeTempSuffix(types::TY_Object)));
+ C.addTempFile(TmpPath);
+ CmdArgs.push_back("-object_path_lto");
+ CmdArgs.push_back(TmpPath);
+ }
+
// Derived from the "link" spec.
Args.AddAllArgs(CmdArgs, options::OPT_static);
if (!Args.hasArg(options::OPT_static))
@@ -2921,6 +3031,7 @@ void darwin::Link::AddLinkArgs(Compilation &C,
Args.AddLastArg(CmdArgs, options::OPT_dynamic);
Args.AddAllArgs(CmdArgs, options::OPT_exported__symbols__list);
Args.AddLastArg(CmdArgs, options::OPT_flat__namespace);
+ Args.AddAllArgs(CmdArgs, options::OPT_force__load);
Args.AddAllArgs(CmdArgs, options::OPT_headerpad__max__install__names);
Args.AddAllArgs(CmdArgs, options::OPT_image__base);
Args.AddAllArgs(CmdArgs, options::OPT_init);
@@ -3142,6 +3253,16 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
getDarwinToolChain().AddLinkSearchPathArgs(Args, CmdArgs);
+ // In ARC, if we don't have runtime support, link in the runtime
+ // stubs. We have to do this *before* adding any of the normal
+ // linker inputs so that its initializer gets run first.
+ if (isObjCAutoRefCount(Args)) {
+ ObjCRuntime runtime;
+ getDarwinToolChain().configureObjCRuntime(runtime);
+ if (!runtime.HasARC)
+ getDarwinToolChain().AddLinkARCArgs(Args, CmdArgs);
+ }
+
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs);
if (LinkingOutput) {
@@ -3170,7 +3291,7 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
// endfile_spec is empty.
}
- addProfileRT(getToolChain(), Args, CmdArgs);
+ addProfileRT(getToolChain(), Args, CmdArgs, getToolChain().getTriple());
Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
Args.AddAllArgs(CmdArgs, options::OPT_F);
@@ -3329,7 +3450,7 @@ void auroraux::Link::ConstructJob(Compilation &C, const JobAction &JA,
getToolChain().GetFilePath("crtend.o")));
}
- addProfileRT(getToolChain(), Args, CmdArgs);
+ addProfileRT(getToolChain(), Args, CmdArgs, getToolChain().getTriple());
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath("ld"));
@@ -3637,7 +3758,7 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
"crtn.o")));
}
- addProfileRT(getToolChain(), Args, CmdArgs);
+ addProfileRT(getToolChain(), Args, CmdArgs, getToolChain().getTriple());
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath("ld"));
@@ -3792,7 +3913,7 @@ void netbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
"crtn.o")));
}
- addProfileRT(getToolChain(), Args, CmdArgs);
+ addProfileRT(getToolChain(), Args, CmdArgs, getToolChain().getTriple());
const char *Exec = Args.MakeArgString(FindTargetProgramPath(getToolChain(),
ToolTriple.getTriple(),
@@ -4016,7 +4137,7 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
}
}
- addProfileRT(getToolChain(), Args, CmdArgs);
+ addProfileRT(getToolChain(), Args, CmdArgs, getToolChain().getTriple());
if (Args.hasArg(options::OPT_use_gold_plugin)) {
CmdArgs.push_back("-plugin");
@@ -4100,7 +4221,7 @@ void minix::Link::ConstructJob(Compilation &C, const JobAction &JA,
"/usr/gnu/lib/libend.a")));
}
- addProfileRT(getToolChain(), Args, CmdArgs);
+ addProfileRT(getToolChain(), Args, CmdArgs, getToolChain().getTriple());
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath("/usr/gnu/bin/gld"));
@@ -4257,7 +4378,7 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA,
getToolChain().GetFilePath("crtn.o")));
}
- addProfileRT(getToolChain(), Args, CmdArgs);
+ addProfileRT(getToolChain(), Args, CmdArgs, getToolChain().getTriple());
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath("ld"));
diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h
index 4a5a7e474526..1741d051ce9f 100644
--- a/lib/Driver/Tools.h
+++ b/lib/Driver/Tools.h
@@ -360,7 +360,7 @@ namespace netbsd {
public:
Link(const ToolChain &TC, const llvm::Triple &ToolTriple)
- : Tool("netbsd::Ling", "linker", TC), ToolTriple(ToolTriple) {}
+ : Tool("netbsd::Link", "linker", TC), ToolTriple(ToolTriple) {}
virtual bool hasIntegratedCPP() const { return false; }
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index 8827116f2e40..5b0a52c65b84 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -102,7 +102,7 @@ ASTUnit::ASTUnit(bool _MainFileIsAST)
ConcurrencyCheckValue(CheckUnlocked),
PreambleRebuildCounter(0), SavedMainFileBuffer(0), PreambleBuffer(0),
ShouldCacheCodeCompletionResults(false),
- NestedMacroInstantiations(true),
+ NestedMacroExpansions(true),
CompletionCacheTopLevelHashValue(0),
PreambleTopLevelHashValue(0),
CurrentTopLevelHashValue(0),
@@ -182,6 +182,10 @@ static unsigned getDeclShowContexts(NamedDecl *ND,
// all types are available due to functional casts.
if (LangOpts.CPlusPlus || isa<ObjCInterfaceDecl>(ND))
Contexts |= (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1));
+
+ // In Objective-C, you can only be a subclass of another Objective-C class
+ if (isa<ObjCInterfaceDecl>(ND))
+ Contexts |= (1 << (CodeCompletionContext::CCC_ObjCSuperclass - 1));
// Deal with tag names.
if (isa<EnumDecl>(ND)) {
@@ -208,6 +212,8 @@ static unsigned getDeclShowContexts(NamedDecl *ND,
| (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1));
} else if (isa<ObjCProtocolDecl>(ND)) {
Contexts = (1 << (CodeCompletionContext::CCC_ObjCProtocolName - 1));
+ } else if (isa<ObjCCategoryDecl>(ND)) {
+ Contexts = (1 << (CodeCompletionContext::CCC_ObjCCategoryName - 1));
} else if (isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND)) {
Contexts = (1 << (CodeCompletionContext::CCC_Namespace - 1));
@@ -928,8 +934,8 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
// If the main file has been overridden due to the use of a preamble,
// make that override happen and introduce the preamble.
PreprocessorOptions &PreprocessorOpts = Clang->getPreprocessorOpts();
- PreprocessorOpts.DetailedRecordIncludesNestedMacroInstantiations
- = NestedMacroInstantiations;
+ PreprocessorOpts.DetailedRecordIncludesNestedMacroExpansions
+ = NestedMacroExpansions;
std::string PriorImplicitPCHInclude;
if (OverrideMainBuffer) {
PreprocessorOpts.addRemappedFile(OriginalSourceFile, OverrideMainBuffer);
@@ -1150,16 +1156,19 @@ static llvm::MemoryBuffer *CreatePaddedMainFileBuffer(llvm::MemoryBuffer *Old,
/// buffer that should be used in place of the main file when doing so.
/// Otherwise, returns a NULL pointer.
llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
- CompilerInvocation PreambleInvocation,
+ const CompilerInvocation &PreambleInvocationIn,
bool AllowRebuild,
unsigned MaxLines) {
- FrontendOptions &FrontendOpts = PreambleInvocation.getFrontendOpts();
+
+ llvm::IntrusiveRefCntPtr<CompilerInvocation>
+ PreambleInvocation(new CompilerInvocation(PreambleInvocationIn));
+ FrontendOptions &FrontendOpts = PreambleInvocation->getFrontendOpts();
PreprocessorOptions &PreprocessorOpts
- = PreambleInvocation.getPreprocessorOpts();
+ = PreambleInvocation->getPreprocessorOpts();
bool CreatedPreambleBuffer = false;
std::pair<llvm::MemoryBuffer *, std::pair<unsigned, bool> > NewPreamble
- = ComputePreamble(PreambleInvocation, MaxLines, CreatedPreambleBuffer);
+ = ComputePreamble(*PreambleInvocation, MaxLines, CreatedPreambleBuffer);
// If ComputePreamble() Take ownership of the
llvm::OwningPtr<llvm::MemoryBuffer> OwnedPreambleBuffer;
@@ -1260,7 +1269,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
// have occurred in the preamble.
getDiagnostics().Reset();
ProcessWarningOptions(getDiagnostics(),
- PreambleInvocation.getDiagnosticOpts());
+ PreambleInvocation->getDiagnosticOpts());
getDiagnostics().setNumWarnings(NumWarningsInPreamble);
if (StoredDiagnostics.size() > NumStoredDiagnosticsInPreamble)
StoredDiagnostics.erase(
@@ -1357,7 +1366,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance>
CICleanup(Clang.get());
- Clang->setInvocation(&PreambleInvocation);
+ Clang->setInvocation(&*PreambleInvocation);
OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].second;
// Set up diagnostics, capturing all of the diagnostics produced.
@@ -1716,7 +1725,7 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
bool PrecompilePreamble,
bool CompleteTranslationUnit,
bool CacheCodeCompletionResults,
- bool NestedMacroInstantiations) {
+ bool NestedMacroExpansions) {
// Create the AST unit.
llvm::OwningPtr<ASTUnit> AST;
AST.reset(new ASTUnit(false));
@@ -1727,7 +1736,7 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
AST->CompleteTranslationUnit = CompleteTranslationUnit;
AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults;
AST->Invocation = CI;
- AST->NestedMacroInstantiations = NestedMacroInstantiations;
+ AST->NestedMacroExpansions = NestedMacroExpansions;
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit>
@@ -1753,7 +1762,7 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
bool CacheCodeCompletionResults,
bool CXXPrecompilePreamble,
bool CXXChainedPCH,
- bool NestedMacroInstantiations) {
+ bool NestedMacroExpansions) {
if (!Diags.getPtr()) {
// No diagnostics engine was provided, so create our own diagnostics object
// with the default options.
@@ -1820,7 +1829,7 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
AST->NumStoredDiagnosticsInPreamble = StoredDiagnostics.size();
AST->StoredDiagnostics.swap(StoredDiagnostics);
AST->Invocation = CI;
- AST->NestedMacroInstantiations = NestedMacroInstantiations;
+ AST->NestedMacroExpansions = NestedMacroExpansions;
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit>
@@ -1899,7 +1908,7 @@ namespace {
/// results from an ASTUnit with the code-completion results provided to it,
/// then passes the result on to
class AugmentedCodeCompleteConsumer : public CodeCompleteConsumer {
- unsigned NormalContexts;
+ unsigned long long NormalContexts;
ASTUnit &AST;
CodeCompleteConsumer &Next;
@@ -1913,22 +1922,24 @@ namespace {
// Compute the set of contexts in which we will look when we don't have
// any information about the specific context.
NormalContexts
- = (1 << (CodeCompletionContext::CCC_TopLevel - 1))
- | (1 << (CodeCompletionContext::CCC_ObjCInterface - 1))
- | (1 << (CodeCompletionContext::CCC_ObjCImplementation - 1))
- | (1 << (CodeCompletionContext::CCC_ObjCIvarList - 1))
- | (1 << (CodeCompletionContext::CCC_Statement - 1))
- | (1 << (CodeCompletionContext::CCC_Expression - 1))
- | (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1))
- | (1 << (CodeCompletionContext::CCC_MemberAccess - 1))
- | (1 << (CodeCompletionContext::CCC_ObjCProtocolName - 1))
- | (1 << (CodeCompletionContext::CCC_ParenthesizedExpression - 1))
- | (1 << (CodeCompletionContext::CCC_Recovery - 1));
+ = (1LL << (CodeCompletionContext::CCC_TopLevel - 1))
+ | (1LL << (CodeCompletionContext::CCC_ObjCInterface - 1))
+ | (1LL << (CodeCompletionContext::CCC_ObjCImplementation - 1))
+ | (1LL << (CodeCompletionContext::CCC_ObjCIvarList - 1))
+ | (1LL << (CodeCompletionContext::CCC_Statement - 1))
+ | (1LL << (CodeCompletionContext::CCC_Expression - 1))
+ | (1LL << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1))
+ | (1LL << (CodeCompletionContext::CCC_DotMemberAccess - 1))
+ | (1LL << (CodeCompletionContext::CCC_ArrowMemberAccess - 1))
+ | (1LL << (CodeCompletionContext::CCC_ObjCPropertyAccess - 1))
+ | (1LL << (CodeCompletionContext::CCC_ObjCProtocolName - 1))
+ | (1LL << (CodeCompletionContext::CCC_ParenthesizedExpression - 1))
+ | (1LL << (CodeCompletionContext::CCC_Recovery - 1));
if (AST.getASTContext().getLangOptions().CPlusPlus)
- NormalContexts |= (1 << (CodeCompletionContext::CCC_EnumTag - 1))
- | (1 << (CodeCompletionContext::CCC_UnionTag - 1))
- | (1 << (CodeCompletionContext::CCC_ClassOrStructTag - 1));
+ NormalContexts |= (1LL << (CodeCompletionContext::CCC_EnumTag - 1))
+ | (1LL << (CodeCompletionContext::CCC_UnionTag - 1))
+ | (1LL << (CodeCompletionContext::CCC_ClassOrStructTag - 1));
}
virtual void ProcessCodeCompleteResults(Sema &S,
@@ -1966,12 +1977,15 @@ static void CalculateHiddenNames(const CodeCompletionContext &Context,
case CodeCompletionContext::CCC_Statement:
case CodeCompletionContext::CCC_Expression:
case CodeCompletionContext::CCC_ObjCMessageReceiver:
- case CodeCompletionContext::CCC_MemberAccess:
+ case CodeCompletionContext::CCC_DotMemberAccess:
+ case CodeCompletionContext::CCC_ArrowMemberAccess:
+ case CodeCompletionContext::CCC_ObjCPropertyAccess:
case CodeCompletionContext::CCC_Namespace:
case CodeCompletionContext::CCC_Type:
case CodeCompletionContext::CCC_Name:
case CodeCompletionContext::CCC_PotentiallyQualifiedName:
case CodeCompletionContext::CCC_ParenthesizedExpression:
+ case CodeCompletionContext::CCC_ObjCSuperclass:
break;
case CodeCompletionContext::CCC_EnumTag:
@@ -1990,6 +2004,9 @@ static void CalculateHiddenNames(const CodeCompletionContext &Context,
case CodeCompletionContext::CCC_TypeQualifiers:
case CodeCompletionContext::CCC_Other:
case CodeCompletionContext::CCC_OtherWithMacros:
+ case CodeCompletionContext::CCC_ObjCInstanceMessage:
+ case CodeCompletionContext::CCC_ObjCClassMessage:
+ case CodeCompletionContext::CCC_ObjCCategoryName:
// We're looking for nothing, or we're looking for names that cannot
// be hidden.
return;
@@ -2284,9 +2301,9 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column,
}
}
-bool ASTUnit::Save(llvm::StringRef File) {
- if (getDiagnostics().hasErrorOccurred())
- return true;
+CXSaveError ASTUnit::Save(llvm::StringRef File) {
+ if (getDiagnostics().hasUnrecoverableErrorOccurred())
+ return CXSaveError_TranslationErrors;
// FIXME: Can we somehow regenerate the stat cache here, or do we need to
// unconditionally create a stat cache when we parse the file?
@@ -2294,11 +2311,11 @@ bool ASTUnit::Save(llvm::StringRef File) {
llvm::raw_fd_ostream Out(File.str().c_str(), ErrorInfo,
llvm::raw_fd_ostream::F_Binary);
if (!ErrorInfo.empty() || Out.has_error())
- return true;
+ return CXSaveError_Unknown;
serialize(Out);
Out.close();
- return Out.has_error();
+ return Out.has_error()? CXSaveError_Unknown : CXSaveError_None;
}
bool ASTUnit::serialize(llvm::raw_ostream &OS) {
diff --git a/lib/Frontend/BoostConAction.cpp b/lib/Frontend/BoostConAction.cpp
deleted file mode 100644
index 4a12ff2ebc95..000000000000
--- a/lib/Frontend/BoostConAction.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-//===-- BoostConAction.cpp - BoostCon Workshop Action -----------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#include "clang/Frontend/FrontendActions.h"
-#include "clang/AST/ASTConsumer.h"
-#include "clang/AST/RecursiveASTVisitor.h"
-#include <cstdio>
-#include <iostream>
-using namespace clang;
-
-namespace {
- class BoostConASTConsumer : public ASTConsumer,
- public RecursiveASTVisitor<BoostConASTConsumer> {
- public:
- /// HandleTranslationUnit - This method is called when the ASTs for entire
- /// translation unit have been parsed.
- virtual void HandleTranslationUnit(ASTContext &Ctx);
-
- bool VisitCXXRecordDecl(CXXRecordDecl *D) {
- std::cout << D->getNameAsString() << std::endl;
- return true;
- }
- };
-}
-
-ASTConsumer *BoostConAction::CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile) {
- return new BoostConASTConsumer();
-}
-
-void BoostConASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
- fprintf(stderr, "Welcome to BoostCon!\n");
- TraverseDecl(Ctx.getTranslationUnitDecl());
-}
diff --git a/lib/Frontend/CMakeLists.txt b/lib/Frontend/CMakeLists.txt
index 7dcbebff39b8..556b1333c19b 100644
--- a/lib/Frontend/CMakeLists.txt
+++ b/lib/Frontend/CMakeLists.txt
@@ -12,7 +12,6 @@ add_clang_library(clangFrontend
ASTConsumers.cpp
ASTMerge.cpp
ASTUnit.cpp
- BoostConAction.cpp
CacheTokens.cpp
CompilerInstance.cpp
CompilerInvocation.cpp
diff --git a/lib/Frontend/CacheTokens.cpp b/lib/Frontend/CacheTokens.cpp
index 06a1fd29838b..20b51893fcc2 100644
--- a/lib/Frontend/CacheTokens.cpp
+++ b/lib/Frontend/CacheTokens.cpp
@@ -247,17 +247,16 @@ void PTHWriter::EmitToken(const Token& T) {
} else {
// We cache *un-cleaned* spellings. This gives us 100% fidelity with the
// source code.
- const char* s = T.getLiteralData();
- unsigned len = T.getLength();
+ llvm::StringRef s(T.getLiteralData(), T.getLength());
// Get the string entry.
- llvm::StringMapEntry<OffsetOpt> *E = &CachedStrs.GetOrCreateValue(s, s+len);
+ llvm::StringMapEntry<OffsetOpt> *E = &CachedStrs.GetOrCreateValue(s);
// If this is a new string entry, bump the PTH offset.
if (!E->getValue().hasOffset()) {
E->getValue().setOffset(CurStrOffset);
StrEntries.push_back(E);
- CurStrOffset += len + 1;
+ CurStrOffset += s.size() + 1;
}
// Emit the relative offset into the PTH file for the spelling string.
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index 38fcfe3c4711..c58e3af5089b 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -38,6 +38,7 @@
#include "llvm/Support/Program.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/system_error.h"
+#include "llvm/Config/config.h"
using namespace clang;
CompilerInstance::CompilerInstance()
@@ -228,7 +229,7 @@ CompilerInstance::createPreprocessor(Diagnostic &Diags,
if (PPOpts.DetailedRecord)
PP->createPreprocessingRecord(
- PPOpts.DetailedRecordIncludesNestedMacroInstantiations);
+ PPOpts.DetailedRecordIncludesNestedMacroExpansions);
InitializePreprocessor(*PP, PPOpts, HSOpts, FEOpts);
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 536512a121e9..06b72602fd18 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -123,6 +123,10 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts,
Res.push_back("-dwarf-debug-flags");
Res.push_back(Opts.DwarfDebugFlags);
}
+ if (Opts.ObjCRuntimeHasARC)
+ Res.push_back("-fobjc-runtime-has-arc");
+ if (Opts.ObjCRuntimeHasTerminate)
+ Res.push_back("-fobjc-runtime-has-terminate");
if (Opts.EmitGcovArcs)
Res.push_back("-femit-coverage-data");
if (Opts.EmitGcovNotes)
@@ -133,6 +137,8 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts,
Res.push_back("-fno-common");
if (Opts.ForbidGuardVariables)
Res.push_back("-fforbid-guard-variables");
+ if (Opts.UseRegisterSizedBitfieldAccess)
+ Res.push_back("-fuse-register-sized-bitfield-access");
if (Opts.NoImplicitFloat)
Res.push_back("-no-implicit-float");
if (Opts.OmitLeafFramePointer)
@@ -169,6 +175,8 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts,
Res.push_back("-fno-use-cxa-atexit");
if (Opts.CXXCtorDtorAliases)
Res.push_back("-mconstructor-aliases");
+ if (Opts.ObjCAutoRefCountExceptions)
+ Res.push_back("-fobjc-arc-eh");
if (!Opts.DebugPass.empty()) {
Res.push_back("-mdebug-pass");
Res.push_back(Opts.DebugPass);
@@ -199,6 +207,8 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts,
Res.push_back("-mregparm");
Res.push_back(llvm::utostr(Opts.NumRegisterParameters));
}
+ if (Opts.NoExecStack)
+ Res.push_back("-mnoexecstack");
if (Opts.RelaxAll)
Res.push_back("-mrelax-all");
if (Opts.SaveTempLabels)
@@ -351,7 +361,6 @@ static const char *getActionName(frontend::ActionKind Kind) {
case frontend::ASTDumpXML: return "-ast-dump-xml";
case frontend::ASTPrint: return "-ast-print";
case frontend::ASTView: return "-ast-view";
- case frontend::BoostCon: return "-boostcon";
case frontend::CreateModule: return "-create-module";
case frontend::DumpRawTokens: return "-dump-raw-tokens";
case frontend::DumpTokens: return "-dump-tokens";
@@ -413,6 +422,23 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts,
Res.push_back("-version");
if (Opts.FixWhatYouCan)
Res.push_back("-fix-what-you-can");
+ switch (Opts.ARCMTAction) {
+ case FrontendOptions::ARCMT_None:
+ break;
+ case FrontendOptions::ARCMT_Check:
+ Res.push_back("-arcmt-check");
+ break;
+ case FrontendOptions::ARCMT_Modify:
+ Res.push_back("-arcmt-modify");
+ break;
+ case FrontendOptions::ARCMT_Migrate:
+ Res.push_back("-arcmt-migrate");
+ break;
+ }
+ if (!Opts.ARCMTMigrateDir.empty()) {
+ Res.push_back("-arcmt-migrate-directory");
+ Res.push_back(Opts.ARCMTMigrateDir);
+ }
bool NeedLang = false;
for (unsigned i = 0, e = Opts.Inputs.size(); i != e; ++i)
@@ -537,6 +563,8 @@ static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts,
Res.push_back("-nostdinc");
if (!Opts.UseStandardCXXIncludes)
Res.push_back("-nostdinc++");
+ if (Opts.UseLibcxx)
+ Res.push_back("-stdlib=libc++");
if (Opts.Verbose)
Res.push_back("-v");
}
@@ -670,8 +698,12 @@ static void LangOptsToArgs(const LangOptions &Opts,
Res.push_back("-fobjc-gc-only");
}
}
- if (Opts.ObjCInferRelatedResultType)
- Res.push_back("-fobjc-infer-related-result-type");
+ if (Opts.ObjCAutoRefCount)
+ Res.push_back("-fobjc-arc");
+ if (Opts.ObjCRuntimeHasWeak)
+ Res.push_back("-fobjc-runtime-has-weak");
+ if (!Opts.ObjCInferRelatedResultType)
+ Res.push_back("-fno-objc-infer-related-result-type");
if (Opts.AppleKext)
Res.push_back("-fapple-kext");
@@ -705,6 +737,8 @@ static void LangOptsToArgs(const LangOptions &Opts,
Res.push_back("-ffake-address-space-map");
if (Opts.ParseUnknownAnytype)
Res.push_back("-funknown-anytype");
+ if (Opts.DebuggerSupport)
+ Res.push_back("-fdebugger-support");
if (Opts.DelayedTemplateParsing)
Res.push_back("-fdelayed-template-parsing");
if (Opts.Deprecated)
@@ -938,6 +972,8 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.DisableLLVMOpts = Args.hasArg(OPT_disable_llvm_optzns);
Opts.DisableRedZone = Args.hasArg(OPT_disable_red_zone);
Opts.ForbidGuardVariables = Args.hasArg(OPT_fforbid_guard_variables);
+ Opts.UseRegisterSizedBitfieldAccess = Args.hasArg(
+ OPT_fuse_register_sized_bitfield_access);
Opts.RelaxedAliasing = Args.hasArg(OPT_relaxed_aliasing);
Opts.DwarfDebugFlags = Args.getLastArgValue(OPT_dwarf_debug_flags);
Opts.MergeAllConstants = !Args.hasArg(OPT_fno_merge_all_constants);
@@ -951,6 +987,9 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
(Opts.OptimizationLevel > 1 && !Opts.OptimizeSize);
Opts.AsmVerbose = Args.hasArg(OPT_masm_verbose);
+ Opts.ObjCAutoRefCountExceptions = Args.hasArg(OPT_fobjc_arc_exceptions);
+ Opts.ObjCRuntimeHasARC = Args.hasArg(OPT_fobjc_runtime_has_arc);
+ Opts.ObjCRuntimeHasTerminate = Args.hasArg(OPT_fobjc_runtime_has_terminate);
Opts.CXAAtExit = !Args.hasArg(OPT_fno_use_cxa_atexit);
Opts.CXXCtorDtorAliases = Args.hasArg(OPT_mconstructor_aliases);
Opts.CodeModel = Args.getLastArgValue(OPT_mcode_model);
@@ -965,6 +1004,7 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.NoZeroInitializedInBSS = Args.hasArg(OPT_mno_zero_initialized_in_bss);
Opts.BackendOptions = Args.getAllArgValues(OPT_backend_option);
Opts.NumRegisterParameters = Args.getLastArgIntValue(OPT_mregparm, 0, Diags);
+ Opts.NoExecStack = Args.hasArg(OPT_mno_exec_stack);
Opts.RelaxAll = Args.hasArg(OPT_mrelax_all);
Opts.OmitLeafFramePointer = Args.hasArg(OPT_momit_leaf_frame_pointer);
Opts.SaveTempLabels = Args.hasArg(OPT_msave_temp_labels);
@@ -1010,6 +1050,7 @@ static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts,
Opts.UsePhonyTargets = Args.hasArg(OPT_MP);
Opts.ShowHeaderIncludes = Args.hasArg(OPT_H);
Opts.HeaderIncludeOutputFile = Args.getLastArgValue(OPT_header_include_file);
+ Opts.AddMissingHeaderDeps = Args.hasArg(OPT_MG);
}
static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
@@ -1117,8 +1158,6 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
Opts.ProgramAction = frontend::ASTPrint; break;
case OPT_ast_view:
Opts.ProgramAction = frontend::ASTView; break;
- case OPT_boostcon:
- Opts.ProgramAction = frontend::BoostCon; break;
case OPT_dump_raw_tokens:
Opts.ProgramAction = frontend::DumpRawTokens; break;
case OPT_dump_tokens:
@@ -1220,6 +1259,26 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
Opts.FixWhatYouCan = Args.hasArg(OPT_fix_what_you_can);
Opts.Modules = Args.getAllArgValues(OPT_import_module);
+ Opts.ARCMTAction = FrontendOptions::ARCMT_None;
+ if (const Arg *A = Args.getLastArg(OPT_arcmt_check,
+ OPT_arcmt_modify,
+ OPT_arcmt_migrate)) {
+ switch (A->getOption().getID()) {
+ default:
+ llvm_unreachable("missed a case");
+ case OPT_arcmt_check:
+ Opts.ARCMTAction = FrontendOptions::ARCMT_Check;
+ break;
+ case OPT_arcmt_modify:
+ Opts.ARCMTAction = FrontendOptions::ARCMT_Modify;
+ break;
+ case OPT_arcmt_migrate:
+ Opts.ARCMTAction = FrontendOptions::ARCMT_Migrate;
+ break;
+ }
+ }
+ Opts.ARCMTMigrateDir = Args.getLastArgValue(OPT_arcmt_migrate_directory);
+
InputKind DashX = IK_None;
if (const Arg *A = Args.getLastArg(OPT_x)) {
DashX = llvm::StringSwitch<InputKind>(A->getValue(Args))
@@ -1291,13 +1350,15 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
Opts.UseBuiltinIncludes = !Args.hasArg(OPT_nobuiltininc);
Opts.UseStandardIncludes = !Args.hasArg(OPT_nostdinc);
Opts.UseStandardCXXIncludes = !Args.hasArg(OPT_nostdincxx);
+ if (const Arg *A = Args.getLastArg(OPT_stdlib_EQ))
+ Opts.UseLibcxx = (strcmp(A->getValue(Args), "libc++") == 0);
Opts.ResourceDir = Args.getLastArgValue(OPT_resource_dir);
// Add -I... and -F... options in order.
for (arg_iterator it = Args.filtered_begin(OPT_I, OPT_F),
ie = Args.filtered_end(); it != ie; ++it)
Opts.AddPath((*it)->getValue(Args), frontend::Angled, true,
- /*IsFramework=*/ (*it)->getOption().matches(OPT_F), true);
+ /*IsFramework=*/ (*it)->getOption().matches(OPT_F), false);
// Add -iprefix/-iwith-prefix/-iwithprefixbefore options.
llvm::StringRef Prefix = ""; // FIXME: This isn't the correct default prefix.
@@ -1309,24 +1370,24 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
Prefix = A->getValue(Args);
else if (A->getOption().matches(OPT_iwithprefix))
Opts.AddPath(Prefix.str() + A->getValue(Args),
- frontend::System, false, false, true);
+ frontend::System, false, false, false);
else
Opts.AddPath(Prefix.str() + A->getValue(Args),
- frontend::Angled, false, false, true);
+ frontend::Angled, false, false, false);
}
for (arg_iterator it = Args.filtered_begin(OPT_idirafter),
ie = Args.filtered_end(); it != ie; ++it)
- Opts.AddPath((*it)->getValue(Args), frontend::After, true, false, true);
+ Opts.AddPath((*it)->getValue(Args), frontend::After, true, false, false);
for (arg_iterator it = Args.filtered_begin(OPT_iquote),
ie = Args.filtered_end(); it != ie; ++it)
- Opts.AddPath((*it)->getValue(Args), frontend::Quoted, true, false, true);
+ Opts.AddPath((*it)->getValue(Args), frontend::Quoted, true, false, false);
for (arg_iterator it = Args.filtered_begin(OPT_cxx_isystem, OPT_isystem,
OPT_iwithsysroot), ie = Args.filtered_end(); it != ie; ++it)
Opts.AddPath((*it)->getValue(Args),
((*it)->getOption().matches(OPT_cxx_isystem) ?
frontend::CXXSystem : frontend::System),
- true, false, (*it)->getOption().matches(OPT_iwithsysroot));
+ true, false, !(*it)->getOption().matches(OPT_iwithsysroot));
// FIXME: Need options for the various environment variables!
}
@@ -1480,17 +1541,27 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
if (Args.hasArg(OPT_fno_operator_names))
Opts.CXXOperatorNames = 0;
+ if (Opts.ObjC1) {
+ if (Args.hasArg(OPT_fobjc_gc_only))
+ Opts.setGCMode(LangOptions::GCOnly);
+ else if (Args.hasArg(OPT_fobjc_gc))
+ Opts.setGCMode(LangOptions::HybridGC);
+ else if (Args.hasArg(OPT_fobjc_arc)) {
+ Opts.ObjCAutoRefCount = 1;
+ if (!Args.hasArg(OPT_fobjc_nonfragile_abi))
+ Diags.Report(diag::err_arc_nonfragile_abi);
+ }
+
+ if (Args.hasArg(OPT_fobjc_runtime_has_weak))
+ Opts.ObjCRuntimeHasWeak = 1;
+
+ if (Args.hasArg(OPT_fno_objc_infer_related_result_type))
+ Opts.ObjCInferRelatedResultType = 0;
+ }
+
if (Args.hasArg(OPT_fgnu89_inline))
Opts.GNUInline = 1;
- if (Args.hasArg(OPT_fobjc_gc_only))
- Opts.setGCMode(LangOptions::GCOnly);
- else if (Args.hasArg(OPT_fobjc_gc))
- Opts.setGCMode(LangOptions::HybridGC);
-
- if (Args.hasArg(OPT_fobjc_infer_related_result_type))
- Opts.ObjCInferRelatedResultType = 1;
-
if (Args.hasArg(OPT_fapple_kext)) {
if (!Opts.CPlusPlus)
Diags.Report(diag::warn_c_kext);
@@ -1598,6 +1669,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.MRTD = Args.hasArg(OPT_mrtd);
Opts.FakeAddressSpaceMap = Args.hasArg(OPT_ffake_address_space_map);
Opts.ParseUnknownAnytype = Args.hasArg(OPT_funknown_anytype);
+ Opts.DebuggerSupport = Args.hasArg(OPT_fdebugger_support);
// Record whether the __DEPRECATED define was requested.
Opts.Deprecated = Args.hasFlag(OPT_fdeprecated_macro,
@@ -1715,6 +1787,19 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
Opts.addRemappedFile(Split.first, Split.second);
}
+
+ if (Arg *A = Args.getLastArg(OPT_fobjc_arc_cxxlib_EQ)) {
+ llvm::StringRef Name = A->getValue(Args);
+ unsigned Library = llvm::StringSwitch<unsigned>(Name)
+ .Case("libc++", ARCXX_libcxx)
+ .Case("libstdc++", ARCXX_libstdcxx)
+ .Case("none", ARCXX_nolib)
+ .Default(~0U);
+ if (Library == ~0U)
+ Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name;
+ else
+ Opts.ObjCXXARCStandardLibrary = (ObjCXXARCStandardLibraryKind)Library;
+ }
}
static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts,
diff --git a/lib/Frontend/DependencyFile.cpp b/lib/Frontend/DependencyFile.cpp
index 5c3a23128a14..1edd09b06c4c 100644
--- a/lib/Frontend/DependencyFile.cpp
+++ b/lib/Frontend/DependencyFile.cpp
@@ -17,9 +17,11 @@
#include "clang/Frontend/DependencyOutputOptions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Lex/DirectoryLookup.h"
+#include "clang/Lex/LexDiagnostic.h"
#include "clang/Lex/PPCallbacks.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/StringSet.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -33,9 +35,11 @@ class DependencyFileCallback : public PPCallbacks {
llvm::raw_ostream *OS;
bool IncludeSystemHeaders;
bool PhonyTarget;
+ bool AddMissingHeaderDeps;
private:
bool FileMatchesDepCriteria(const char *Filename,
SrcMgr::CharacteristicKind FileType);
+ void AddFilename(llvm::StringRef Filename);
void OutputDependencyFile();
public:
@@ -44,10 +48,19 @@ public:
const DependencyOutputOptions &Opts)
: PP(_PP), Targets(Opts.Targets), OS(_OS),
IncludeSystemHeaders(Opts.IncludeSystemHeaders),
- PhonyTarget(Opts.UsePhonyTargets) {}
+ PhonyTarget(Opts.UsePhonyTargets),
+ AddMissingHeaderDeps(Opts.AddMissingHeaderDeps) {}
virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
SrcMgr::CharacteristicKind FileType);
+ virtual void InclusionDirective(SourceLocation HashLoc,
+ const Token &IncludeTok,
+ llvm::StringRef FileName,
+ bool IsAngled,
+ const FileEntry *File,
+ SourceLocation EndLoc,
+ llvm::StringRef SearchPath,
+ llvm::StringRef RelativePath);
virtual void EndOfMainFile() {
OutputDependencyFile();
@@ -72,6 +85,16 @@ void clang::AttachDependencyFileGen(Preprocessor &PP,
return;
}
+ // Disable the "file not found" diagnostic if the -MG option was given.
+ // FIXME: Ideally this would live in the driver, but we don't have the ability
+ // to remap individual diagnostics there without creating a DiagGroup, in
+ // which case we would need to prevent the group name from showing up in
+ // diagnostics.
+ if (Opts.AddMissingHeaderDeps) {
+ PP.getDiagnostics().setDiagnosticMapping(diag::warn_pp_file_not_found,
+ diag::MAP_IGNORE, SourceLocation());
+ }
+
PP.addPPCallbacks(new DependencyFileCallback(&PP, OS, Opts));
}
@@ -103,14 +126,34 @@ void DependencyFileCallback::FileChanged(SourceLocation Loc,
SM.getFileEntryForID(SM.getFileID(SM.getInstantiationLoc(Loc)));
if (FE == 0) return;
- const char *Filename = FE->getName();
- if (!FileMatchesDepCriteria(Filename, FileType))
+ llvm::StringRef Filename = FE->getName();
+ if (!FileMatchesDepCriteria(Filename.data(), FileType))
return;
- // Remove leading "./"
- if (Filename[0] == '.' && Filename[1] == '/')
- Filename = &Filename[2];
+ // Remove leading "./" (or ".//" or "././" etc.)
+ while (Filename.size() > 2 && Filename[0] == '.' &&
+ llvm::sys::path::is_separator(Filename[1])) {
+ Filename = Filename.substr(1);
+ while (llvm::sys::path::is_separator(Filename[0]))
+ Filename = Filename.substr(1);
+ }
+
+ AddFilename(Filename);
+}
+
+void DependencyFileCallback::InclusionDirective(SourceLocation HashLoc,
+ const Token &IncludeTok,
+ llvm::StringRef FileName,
+ bool IsAngled,
+ const FileEntry *File,
+ SourceLocation EndLoc,
+ llvm::StringRef SearchPath,
+ llvm::StringRef RelativePath) {
+ if (AddMissingHeaderDeps && !File)
+ AddFilename(FileName);
+}
+void DependencyFileCallback::AddFilename(llvm::StringRef Filename) {
if (FilesSet.insert(Filename))
Files.push_back(Filename);
}
diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp
index 42da44c2c720..0128d6ee0531 100644
--- a/lib/Frontend/FrontendAction.cpp
+++ b/lib/Frontend/FrontendAction.cpp
@@ -130,6 +130,9 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
setCurrentFile(Filename, InputKind);
setCompilerInstance(&CI);
+ if (!BeginInvocation(CI))
+ goto failure;
+
// AST files follow a very different path, since they share objects via the
// AST unit.
if (InputKind == IK_AST) {
@@ -381,3 +384,46 @@ PreprocessorFrontendAction::CreateASTConsumer(CompilerInstance &CI,
llvm::StringRef InFile) {
llvm_unreachable("Invalid CreateASTConsumer on preprocessor action!");
}
+
+ASTConsumer *WrapperFrontendAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ return WrappedAction->CreateASTConsumer(CI, InFile);
+}
+bool WrapperFrontendAction::BeginInvocation(CompilerInstance &CI) {
+ return WrappedAction->BeginInvocation(CI);
+}
+bool WrapperFrontendAction::BeginSourceFileAction(CompilerInstance &CI,
+ llvm::StringRef Filename) {
+ WrappedAction->setCurrentFile(getCurrentFile(), getCurrentFileKind());
+ WrappedAction->setCompilerInstance(&CI);
+ return WrappedAction->BeginSourceFileAction(CI, Filename);
+}
+void WrapperFrontendAction::ExecuteAction() {
+ WrappedAction->ExecuteAction();
+}
+void WrapperFrontendAction::EndSourceFileAction() {
+ WrappedAction->EndSourceFileAction();
+}
+
+bool WrapperFrontendAction::usesPreprocessorOnly() const {
+ return WrappedAction->usesPreprocessorOnly();
+}
+bool WrapperFrontendAction::usesCompleteTranslationUnit() {
+ return WrappedAction->usesCompleteTranslationUnit();
+}
+bool WrapperFrontendAction::hasPCHSupport() const {
+ return WrappedAction->hasPCHSupport();
+}
+bool WrapperFrontendAction::hasASTFileSupport() const {
+ return WrappedAction->hasASTFileSupport();
+}
+bool WrapperFrontendAction::hasIRSupport() const {
+ return WrappedAction->hasIRSupport();
+}
+bool WrapperFrontendAction::hasCodeCompletionSupport() const {
+ return WrappedAction->hasCodeCompletionSupport();
+}
+
+WrapperFrontendAction::WrapperFrontendAction(FrontendAction *WrappedAction)
+ : WrappedAction(WrappedAction) {}
+
diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp
index ad931166b8fc..e11a415db194 100644
--- a/lib/Frontend/InitHeaderSearch.cpp
+++ b/lib/Frontend/InitHeaderSearch.cpp
@@ -45,7 +45,7 @@ class InitHeaderSearch {
std::vector<std::pair<IncludeDirGroup, DirectoryLookup> > IncludePath;
typedef std::vector<std::pair<IncludeDirGroup,
DirectoryLookup> >::const_iterator path_iterator;
- HeaderSearch& Headers;
+ HeaderSearch &Headers;
bool Verbose;
std::string IncludeSysroot;
bool IsNotEmptyOrRoot;
@@ -78,7 +78,8 @@ public:
/// AddMinGW64CXXPaths - Add the necessary paths to support
/// libstdc++ of x86_64-w64-mingw32 aka mingw-w64.
- void AddMinGW64CXXPaths(llvm::StringRef Base);
+ void AddMinGW64CXXPaths(llvm::StringRef Base,
+ llvm::StringRef Version);
/// AddDelimitedPaths - Add a list of paths delimited by the system PATH
/// separator. The processing follows that of the CPATH variable for gcc.
@@ -90,7 +91,8 @@ public:
// AddDefaultCPlusPlusIncludePaths - Add paths that should be searched when
// compiling c++.
- void AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple);
+ void AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple,
+ const HeaderSearchOptions &HSOpts);
/// AddDefaultSystemIncludePaths - Adds the default system include paths so
/// that e.g. stdio.h is found.
@@ -103,7 +105,7 @@ public:
void Realize(const LangOptions &Lang);
};
-}
+} // end anonymous namespace.
void InitHeaderSearch::AddPath(const llvm::Twine &Path,
IncludeDirGroup Group, bool isCXXAware,
@@ -216,12 +218,16 @@ void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(llvm::StringRef Base,
CXXSystem, true, false, false);
}
-void InitHeaderSearch::AddMinGW64CXXPaths(llvm::StringRef Base) {
- AddPath(Base,
+void InitHeaderSearch::AddMinGW64CXXPaths(llvm::StringRef Base,
+ llvm::StringRef Version) {
+ // Assumes Base is HeaderSearchOpts' ResourceDir
+ AddPath(Base + "/../../../include/c++/" + Version,
+ CXXSystem, true, false, false);
+ AddPath(Base + "/../../../include/c++/" + Version + "/x86_64-w64-mingw32",
CXXSystem, true, false, false);
- AddPath(Base + "/x86_64-w64-mingw32",
+ AddPath(Base + "/../../../include/c++/" + Version + "/i686-w64-mingw32",
CXXSystem, true, false, false);
- AddPath(Base + "/backward",
+ AddPath(Base + "/../../../include/c++/" + Version + "/backward",
CXXSystem, true, false, false);
}
@@ -245,24 +251,23 @@ static bool getSystemRegistryString(const char *keyPath, const char *valueName,
DWORD valueSize = maxLength - 1;
long lResult;
bool returnValue = false;
+
if (strncmp(keyPath, "HKEY_CLASSES_ROOT\\", 18) == 0) {
hRootKey = HKEY_CLASSES_ROOT;
subKey = keyPath + 18;
- }
- else if (strncmp(keyPath, "HKEY_USERS\\", 11) == 0) {
+ } else if (strncmp(keyPath, "HKEY_USERS\\", 11) == 0) {
hRootKey = HKEY_USERS;
subKey = keyPath + 11;
- }
- else if (strncmp(keyPath, "HKEY_LOCAL_MACHINE\\", 19) == 0) {
+ } else if (strncmp(keyPath, "HKEY_LOCAL_MACHINE\\", 19) == 0) {
hRootKey = HKEY_LOCAL_MACHINE;
subKey = keyPath + 19;
- }
- else if (strncmp(keyPath, "HKEY_CURRENT_USER\\", 18) == 0) {
+ } else if (strncmp(keyPath, "HKEY_CURRENT_USER\\", 18) == 0) {
hRootKey = HKEY_CURRENT_USER;
subKey = keyPath + 18;
}
else
- return(false);
+ return false;
+
const char *placeHolder = strstr(subKey, "$VERSION");
char bestName[256];
bestName[0] = '\0';
@@ -338,7 +343,7 @@ static bool getSystemRegistryString(const char *keyPath, const char *valueName,
RegCloseKey(hKey);
}
}
- return(returnValue);
+ return returnValue;
}
#else // _MSC_VER
// Read registry string.
@@ -351,12 +356,12 @@ static bool getSystemRegistryString(const char*, const char*, char*, size_t) {
static bool getVisualStudioDir(std::string &path) {
// First check the environment variables that vsvars32.bat sets.
const char* vcinstalldir = getenv("VCINSTALLDIR");
- if(vcinstalldir) {
+ if (vcinstalldir) {
char *p = const_cast<char *>(strstr(vcinstalldir, "\\VC"));
if (p)
*p = '\0';
path = vcinstalldir;
- return(true);
+ return true;
}
char vsIDEInstallDir[256];
@@ -374,56 +379,52 @@ static bool getVisualStudioDir(std::string &path) {
if (p)
*p = '\0';
path = vsIDEInstallDir;
- return(true);
+ return true;
}
- else if (hasVCExpressDir && vsExpressIDEInstallDir[0]) {
+
+ if (hasVCExpressDir && vsExpressIDEInstallDir[0]) {
char *p = (char*)strstr(vsExpressIDEInstallDir, "\\Common7\\IDE");
if (p)
*p = '\0';
path = vsExpressIDEInstallDir;
- return(true);
+ return true;
}
- else {
- // Try the environment.
- const char* vs100comntools = getenv("VS100COMNTOOLS");
- const char* vs90comntools = getenv("VS90COMNTOOLS");
- const char* vs80comntools = getenv("VS80COMNTOOLS");
- const char* vscomntools = NULL;
-
- // Try to find the version that we were compiled with
- if(false) {}
- #if (_MSC_VER >= 1600) // VC100
- else if(vs100comntools) {
- vscomntools = vs100comntools;
- }
- #elif (_MSC_VER == 1500) // VC80
- else if(vs90comntools) {
- vscomntools = vs90comntools;
- }
- #elif (_MSC_VER == 1400) // VC80
- else if(vs80comntools) {
- vscomntools = vs80comntools;
- }
- #endif
- // Otherwise find any version we can
- else if (vs100comntools)
- vscomntools = vs100comntools;
- else if (vs90comntools)
- vscomntools = vs90comntools;
- else if (vs80comntools)
- vscomntools = vs80comntools;
-
- if (vscomntools && *vscomntools) {
- char *p = const_cast<char *>(strstr(vscomntools, "\\Common7\\Tools"));
- if (p)
- *p = '\0';
- path = vscomntools;
- return(true);
- }
- else
- return(false);
+
+ // Try the environment.
+ const char *vs100comntools = getenv("VS100COMNTOOLS");
+ const char *vs90comntools = getenv("VS90COMNTOOLS");
+ const char *vs80comntools = getenv("VS80COMNTOOLS");
+ const char *vscomntools = NULL;
+
+ // Try to find the version that we were compiled with
+ if(false) {}
+ #if (_MSC_VER >= 1600) // VC100
+ else if(vs100comntools) {
+ vscomntools = vs100comntools;
}
- return(false);
+ #elif (_MSC_VER == 1500) // VC80
+ else if(vs90comntools) {
+ vscomntools = vs90comntools;
+ }
+ #elif (_MSC_VER == 1400) // VC80
+ else if(vs80comntools) {
+ vscomntools = vs80comntools;
+ }
+ #endif
+ // Otherwise find any version we can
+ else if (vs100comntools)
+ vscomntools = vs100comntools;
+ else if (vs90comntools)
+ vscomntools = vs90comntools;
+ else if (vs80comntools)
+ vscomntools = vs80comntools;
+
+ if (vscomntools && *vscomntools) {
+ const char *p = strstr(vscomntools, "\\Common7\\Tools");
+ path = p ? std::string(vscomntools, p) : vscomntools;
+ return true;
+ }
+ return false;
}
// Get Windows SDK installation directory.
@@ -432,7 +433,9 @@ static bool getWindowsSDKDir(std::string &path) {
// Try the Windows registry.
bool hasSDKDir = getSystemRegistryString(
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION",
- "InstallationFolder", windowsSDKInstallDir, sizeof(windowsSDKInstallDir) - 1);
+ "InstallationFolder",
+ windowsSDKInstallDir,
+ sizeof(windowsSDKInstallDir) - 1);
// If we have both vc80 and vc90, pick version we were compiled with.
if (hasSDKDir && windowsSDKInstallDir[0]) {
path = windowsSDKInstallDir;
@@ -548,17 +551,28 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
AddPath("/boot/develop/headers/posix", System, true, false, false);
AddPath("/boot/develop/headers", System, true, false, false);
break;
+ case llvm::Triple::RTEMS:
+ break;
case llvm::Triple::Cygwin:
AddPath("/usr/include/w32api", System, true, false, false);
break;
- case llvm::Triple::MinGW32:
- // FIXME: We should be aware of i686-w64-mingw32.
- if (triple.getArch() == llvm::Triple::x86_64)
- AddPath("c:/mingw/x86_64-w64-mingw32/include",
- System, true, false, false);
- AddPath("/mingw/include", System, true, false, false);
- AddPath("c:/mingw/include", System, true, false, false);
+ case llvm::Triple::MinGW32: {
+ // mingw-w64 crt include paths
+ llvm::sys::Path P(HSOpts.ResourceDir);
+ P.appendComponent("../../../i686-w64-mingw32/include"); // <sysroot>/i686-w64-mingw32/include
+ AddPath(P.str(), System, true, false, false);
+ P = llvm::sys::Path(HSOpts.ResourceDir);
+ P.appendComponent("../../../x86_64-w64-mingw32/include"); // <sysroot>/x86_64-w64-mingw32/include
+ AddPath(P.str(), System, true, false, false);
+ // mingw.org crt include paths
+ P = llvm::sys::Path(HSOpts.ResourceDir);
+ P.appendComponent("../../../include"); // <sysroot>/include
+ AddPath(P.str(), System, true, false, false);
+ AddPath("/mingw/include", System, true, false, false);
+ AddPath("c:/mingw/include", System, true, false, false);
+ }
break;
+
case llvm::Triple::Linux:
// Generic Debian multiarch support:
if (triple.getArch() == llvm::Triple::x86_64) {
@@ -576,11 +590,12 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
break;
}
- AddPath("/usr/include", System, false, false, false);
+ if ( os != llvm::Triple::RTEMS )
+ AddPath("/usr/include", System, false, false, false);
}
void InitHeaderSearch::
-AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) {
+AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple, const HeaderSearchOptions &HSOpts) {
llvm::Triple::OSType os = triple.getOS();
llvm::StringRef CxxIncludeRoot(CXX_INCLUDE_ROOT);
if (CxxIncludeRoot != "") {
@@ -640,20 +655,19 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) {
AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "3.4.4");
break;
case llvm::Triple::MinGW32:
- // FIXME: We should be aware of i686-w64-mingw32.
- if (triple.getArch() == llvm::Triple::x86_64) {
- // mingw-w64-20110207
- AddMinGW64CXXPaths("c:/mingw/x86_64-w64-mingw32/include/c++/4.5.3");
- // mingw-w64-20101129
- AddMinGW64CXXPaths("c:/mingw/x86_64-w64-mingw32/include/c++/4.5.2");
- }
- // Try gcc 4.5.2 (MSYS)
- AddMinGWCPlusPlusIncludePaths("/mingw/lib/gcc", "mingw32", "4.5.2");
- // Try gcc 4.5.0
+ // mingw-w64 C++ include paths (i686-w64-mingw32 and x86_64-w64-mingw32)
+ AddMinGW64CXXPaths(HSOpts.ResourceDir, "4.5.0");
+ AddMinGW64CXXPaths(HSOpts.ResourceDir, "4.5.1");
+ AddMinGW64CXXPaths(HSOpts.ResourceDir, "4.5.2");
+ AddMinGW64CXXPaths(HSOpts.ResourceDir, "4.5.3");
+ AddMinGW64CXXPaths(HSOpts.ResourceDir, "4.6.0");
+ AddMinGW64CXXPaths(HSOpts.ResourceDir, "4.6.1");
+ AddMinGW64CXXPaths(HSOpts.ResourceDir, "4.6.2");
+ AddMinGW64CXXPaths(HSOpts.ResourceDir, "4.7.0");
+ // mingw.org C++ include paths
+ AddMinGWCPlusPlusIncludePaths("/mingw/lib/gcc", "mingw32", "4.5.2"); //MSYS
AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.5.0");
- // Try gcc 4.4.0
AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.4.0");
- // Try gcc 4.3.0
AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.3.0");
break;
case llvm::Triple::DragonFly:
@@ -733,6 +747,9 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) {
"x86_64-redhat-linux", "32", "", triple);
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5.1",
"i686-redhat-linux", "", "", triple);
+ // RHEL5(gcc44)
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.4",
+ "x86_64-redhat-linux6E", "32", "", triple);
// Fedora 13
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.4",
"x86_64-redhat-linux", "32", "", triple);
@@ -814,6 +831,10 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) {
"x86_64-unknown-linux-gnu", "", "", triple);
// Arch Linux gcc 4.6
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6.1",
+ "i686-pc-linux-gnu", "", "", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6.1",
+ "x86_64-unknown-linux-gnu", "", "", triple);
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6.0",
"i686-pc-linux-gnu", "", "", triple);
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6.0",
@@ -918,8 +939,12 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) {
void InitHeaderSearch::AddDefaultSystemIncludePaths(const LangOptions &Lang,
const llvm::Triple &triple,
const HeaderSearchOptions &HSOpts) {
- if (Lang.CPlusPlus && HSOpts.UseStandardCXXIncludes)
- AddDefaultCPlusPlusIncludePaths(triple);
+ if (Lang.CPlusPlus && HSOpts.UseStandardCXXIncludes) {
+ if (HSOpts.UseLibcxx)
+ AddPath("/usr/include/c++/v1", CXXSystem, true, false, false);
+ else
+ AddDefaultCPlusPlusIncludePaths(triple, HSOpts);
+ }
AddDefaultCIncludePaths(triple, HSOpts);
@@ -1017,23 +1042,24 @@ void InitHeaderSearch::Realize(const LangOptions &Lang) {
std::vector<DirectoryLookup> SearchList;
SearchList.reserve(IncludePath.size());
- /* Quoted arguments go first. */
+ // Quoted arguments go first.
for (path_iterator it = IncludePath.begin(), ie = IncludePath.end();
it != ie; ++it) {
if (it->first == Quoted)
SearchList.push_back(it->second);
}
- /* Deduplicate and remember index */
+ // Deduplicate and remember index.
RemoveDuplicates(SearchList, 0, Verbose);
- unsigned quoted = SearchList.size();
+ unsigned NumQuoted = SearchList.size();
for (path_iterator it = IncludePath.begin(), ie = IncludePath.end();
it != ie; ++it) {
if (it->first == Angled)
SearchList.push_back(it->second);
}
- RemoveDuplicates(SearchList, quoted, Verbose);
- unsigned angled = SearchList.size();
+
+ RemoveDuplicates(SearchList, NumQuoted, Verbose);
+ unsigned NumAngled = SearchList.size();
for (path_iterator it = IncludePath.begin(), ie = IncludePath.end();
it != ie; ++it) {
@@ -1047,16 +1073,19 @@ void InitHeaderSearch::Realize(const LangOptions &Lang) {
SearchList.push_back(it->second);
}
- RemoveDuplicates(SearchList, angled, Verbose);
+ // Remove duplicates across both the Angled and System directories. GCC does
+ // this and failing to remove duplicates across these two groups breaks
+ // #include_next.
+ RemoveDuplicates(SearchList, NumQuoted, Verbose);
bool DontSearchCurDir = false; // TODO: set to true if -I- is set?
- Headers.SetSearchPaths(SearchList, quoted, angled, DontSearchCurDir);
+ Headers.SetSearchPaths(SearchList, NumQuoted, NumAngled, DontSearchCurDir);
// If verbose, print the list of directories that will be searched.
if (Verbose) {
llvm::errs() << "#include \"...\" search starts here:\n";
for (unsigned i = 0, e = SearchList.size(); i != e; ++i) {
- if (i == quoted)
+ if (i == NumQuoted)
llvm::errs() << "#include <...> search starts here:\n";
const char *Name = SearchList[i].getName();
const char *Suffix;
@@ -1084,7 +1113,7 @@ void clang::ApplyHeaderSearchOptions(HeaderSearch &HS,
for (unsigned i = 0, e = HSOpts.UserEntries.size(); i != e; ++i) {
const HeaderSearchOptions::Entry &E = HSOpts.UserEntries[i];
Init.AddPath(E.Path, E.Group, false, E.IsUserSupplied, E.IsFramework,
- !E.IsSysRootRelative);
+ E.IgnoreSysRoot);
}
// Add entries from CPATH and friends.
diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp
index 147a8df03760..9428cd5de0f3 100644
--- a/lib/Frontend/InitPreprocessor.cpp
+++ b/lib/Frontend/InitPreprocessor.cpp
@@ -221,6 +221,125 @@ static void DefineExactWidthIntType(TargetInfo::IntType Ty,
ConstSuffix);
}
+/// \brief Add definitions required for a smooth interaction between
+/// Objective-C++ automatic reference counting and libc++.
+static void AddObjCXXARCLibcxxDefines(const LangOptions &LangOpts,
+ MacroBuilder &Builder) {
+ Builder.defineMacro("_LIBCPP_PREDEFINED_OBJC_ARC_ADDRESSOF");
+
+ std::string Result;
+ {
+ // Provide overloads of the function std::__1::addressof() that accept
+ // references to lifetime-qualified objects. libc++'s (more general)
+ // std::__1::addressof() template fails to instantiate with such types,
+ // because it attempts to convert the object to a char& before
+ // dereferencing.
+ llvm::raw_string_ostream Out(Result);
+
+ Out << "#pragma clang diagnostic push\n"
+ << "#pragma clang diagnostic ignored \"-Wc++0x-extensions\"\n"
+ << "namespace std { inline namespace __1 {\n"
+ << "\n";
+
+ Out << "template <class _Tp>\n"
+ << "inline __attribute__ ((__visibility__(\"hidden\"), "
+ << "__always_inline__))\n"
+ << "__attribute__((objc_ownership(strong))) _Tp*\n"
+ << "addressof(__attribute__((objc_ownership(strong))) _Tp& __x) {\n"
+ << " return &__x;\n"
+ << "}\n"
+ << "\n";
+
+ if (LangOpts.ObjCRuntimeHasWeak) {
+ Out << "template <class _Tp>\n"
+ << "inline __attribute__ ((__visibility__(\"hidden\"),"
+ << "__always_inline__))\n"
+ << "__attribute__((objc_ownership(weak))) _Tp*\n"
+ << "addressof(__attribute__((objc_ownership(weak))) _Tp& __x) {\n"
+ << " return &__x;\n"
+ << "};\n"
+ << "\n";
+ }
+
+ Out << "template <class _Tp>\n"
+ << "inline __attribute__ ((__visibility__(\"hidden\"),"
+ << "__always_inline__))\n"
+ << "__attribute__((objc_ownership(autoreleasing))) _Tp*\n"
+ << "addressof(__attribute__((objc_ownership(autoreleasing))) _Tp& __x) "
+ << "{\n"
+ << " return &__x;\n"
+ << "}\n"
+ << "\n";
+
+ Out << "template <class _Tp>\n"
+ << "inline __attribute__ ((__visibility__(\"hidden\"), "
+ << "__always_inline__))\n"
+ << "__unsafe_unretained _Tp* addressof(__unsafe_unretained _Tp& __x)"
+ << " {\n"
+ << " return &__x;\n"
+ << "}\n";
+
+ Out << "\n"
+ << "} }\n"
+ << "#pragma clang diagnostic pop\n"
+ << "\n";
+ }
+ Builder.append(Result);
+}
+
+/// \brief Add definitions required for a smooth interaction between
+/// Objective-C++ automated reference counting and libstdc++ (4.2).
+static void AddObjCXXARCLibstdcxxDefines(const LangOptions &LangOpts,
+ MacroBuilder &Builder) {
+ Builder.defineMacro("_GLIBCXX_PREDEFINED_OBJC_ARC_IS_SCALAR");
+
+ std::string Result;
+ {
+ // Provide specializations for the __is_scalar type trait so that
+ // lifetime-qualified objects are not considered "scalar" types, which
+ // libstdc++ uses as an indicator of the presence of trivial copy, assign,
+ // default-construct, and destruct semantics (none of which hold for
+ // lifetime-qualified objects in ARC).
+ llvm::raw_string_ostream Out(Result);
+
+ Out << "namespace std {\n"
+ << "\n"
+ << "struct __true_type;\n"
+ << "struct __false_type;\n"
+ << "\n";
+
+ Out << "template<typename _Tp> struct __is_scalar;\n"
+ << "\n";
+
+ Out << "template<typename _Tp>\n"
+ << "struct __is_scalar<__attribute__((objc_ownership(strong))) _Tp> {\n"
+ << " enum { __value = 0 };\n"
+ << " typedef __false_type __type;\n"
+ << "};\n"
+ << "\n";
+
+ if (LangOpts.ObjCRuntimeHasWeak) {
+ Out << "template<typename _Tp>\n"
+ << "struct __is_scalar<__attribute__((objc_ownership(weak))) _Tp> {\n"
+ << " enum { __value = 0 };\n"
+ << " typedef __false_type __type;\n"
+ << "};\n"
+ << "\n";
+ }
+
+ Out << "template<typename _Tp>\n"
+ << "struct __is_scalar<__attribute__((objc_ownership(autoreleasing)))"
+ << " _Tp> {\n"
+ << " enum { __value = 0 };\n"
+ << " typedef __false_type __type;\n"
+ << "};\n"
+ << "\n";
+
+ Out << "}\n";
+ }
+ Builder.append(Result);
+}
+
static void InitializeStandardPredefinedMacros(const TargetInfo &TI,
const LangOptions &LangOpts,
const FrontendOptions &FEOpts,
@@ -240,11 +359,18 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI,
} else {
if (LangOpts.GNUMode)
Builder.defineMacro("__cplusplus");
- else
- // C++ [cpp.predefined]p1:
+ else {
+ // C++0x [cpp.predefined]p1:
+ // The name_ _cplusplus is defined to the value 201103L when compiling a
+ // C++ translation unit.
+ if (LangOpts.CPlusPlus0x)
+ Builder.defineMacro("__cplusplus", "201103L");
+ // C++03 [cpp.predefined]p1:
// The name_ _cplusplus is defined to the value 199711L when compiling a
// C++ translation unit.
- Builder.defineMacro("__cplusplus", "199711L");
+ else
+ Builder.defineMacro("__cplusplus", "199711L");
+ }
}
if (LangOpts.ObjC1)
@@ -312,7 +438,8 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
// darwin_constant_cfstrings controls this. This is also dependent
// on other things like the runtime I believe. This is set even for C code.
- Builder.defineMacro("__CONSTANT_CFSTRINGS__");
+ if (!LangOpts.NoConstantCFStrings)
+ Builder.defineMacro("__CONSTANT_CFSTRINGS__");
if (LangOpts.ObjC2)
Builder.defineMacro("OBJC_NEW_PROPERTIES");
@@ -487,6 +614,15 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
if (LangOpts.FastRelaxedMath)
Builder.defineMacro("__FAST_RELAXED_MATH__");
+ if (LangOpts.ObjCAutoRefCount) {
+ Builder.defineMacro("__weak", "__attribute__((objc_ownership(weak)))");
+ Builder.defineMacro("__strong", "__attribute__((objc_ownership(strong)))");
+ Builder.defineMacro("__autoreleasing",
+ "__attribute__((objc_ownership(autoreleasing)))");
+ Builder.defineMacro("__unsafe_unretained",
+ "__attribute__((objc_ownership(none)))");
+ }
+
// Get other target #defines.
TI.getTargetDefines(LangOpts, Builder);
}
@@ -560,6 +696,7 @@ void clang::InitializePreprocessor(Preprocessor &PP,
const PreprocessorOptions &InitOpts,
const HeaderSearchOptions &HSOpts,
const FrontendOptions &FEOpts) {
+ const LangOptions &LangOpts = PP.getLangOptions();
std::string PredefineBuffer;
PredefineBuffer.reserve(4080);
llvm::raw_string_ostream Predefines(PredefineBuffer);
@@ -575,10 +712,27 @@ void clang::InitializePreprocessor(Preprocessor &PP,
Builder.append("# 1 \"<built-in>\" 3");
// Install things like __POWERPC__, __GNUC__, etc into the macro table.
- if (InitOpts.UsePredefines)
- InitializePredefinedMacros(PP.getTargetInfo(), PP.getLangOptions(),
- FEOpts, Builder);
-
+ if (InitOpts.UsePredefines) {
+ InitializePredefinedMacros(PP.getTargetInfo(), LangOpts, FEOpts, Builder);
+
+ // Install definitions to make Objective-C++ ARC work well with various
+ // C++ Standard Library implementations.
+ if (LangOpts.ObjC1 && LangOpts.CPlusPlus && LangOpts.ObjCAutoRefCount) {
+ switch (InitOpts.ObjCXXARCStandardLibrary) {
+ case ARCXX_nolib:
+ break;
+
+ case ARCXX_libcxx:
+ AddObjCXXARCLibcxxDefines(LangOpts, Builder);
+ break;
+
+ case ARCXX_libstdcxx:
+ AddObjCXXARCLibstdcxxDefines(LangOpts, Builder);
+ break;
+ }
+ }
+ }
+
// Even with predefines off, some macros are still predefined.
// These should all be defined in the preprocessor according to the
// current language configuration.
diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp
index b46e04749ba3..c892960a18b9 100644
--- a/lib/Frontend/PrintPreprocessedOutput.cpp
+++ b/lib/Frontend/PrintPreprocessedOutput.cpp
@@ -26,6 +26,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Config/config.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/ErrorHandling.h"
#include <cstdio>
using namespace clang;
@@ -122,6 +123,12 @@ public:
virtual void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind,
const std::string &Str);
virtual void PragmaMessage(SourceLocation Loc, llvm::StringRef Str);
+ virtual void PragmaDiagnosticPush(SourceLocation Loc,
+ llvm::StringRef Namespace);
+ virtual void PragmaDiagnosticPop(SourceLocation Loc,
+ llvm::StringRef Namespace);
+ virtual void PragmaDiagnostic(SourceLocation Loc, llvm::StringRef Namespace,
+ diag::Mapping Map, llvm::StringRef Str);
bool HandleFirstTokOnLine(Token &Tok);
bool MoveToLine(SourceLocation Loc) {
@@ -189,7 +196,7 @@ bool PrintPPOutputPPCallbacks::MoveToLine(unsigned LineNo) {
if (LineNo-CurLine == 1)
OS << '\n';
else if (LineNo == CurLine)
- return false; // Spelling line moved, but instantiation line didn't.
+ return false; // Spelling line moved, but expansion line didn't.
else {
const char *NewLines = "\n\n\n\n\n\n\n\n";
OS.write(NewLines, LineNo-CurLine);
@@ -361,12 +368,49 @@ void PrintPPOutputPPCallbacks::PragmaMessage(SourceLocation Loc,
EmittedTokensOnThisLine = true;
}
+void PrintPPOutputPPCallbacks::
+PragmaDiagnosticPush(SourceLocation Loc, llvm::StringRef Namespace) {
+ MoveToLine(Loc);
+ OS << "#pragma " << Namespace << " diagnostic push";
+ EmittedTokensOnThisLine = true;
+}
+
+void PrintPPOutputPPCallbacks::
+PragmaDiagnosticPop(SourceLocation Loc, llvm::StringRef Namespace) {
+ MoveToLine(Loc);
+ OS << "#pragma " << Namespace << " diagnostic pop";
+ EmittedTokensOnThisLine = true;
+}
+
+void PrintPPOutputPPCallbacks::
+PragmaDiagnostic(SourceLocation Loc, llvm::StringRef Namespace,
+ diag::Mapping Map, llvm::StringRef Str) {
+ MoveToLine(Loc);
+ OS << "#pragma " << Namespace << " diagnostic ";
+ switch (Map) {
+ default: llvm_unreachable("unexpected diagnostic kind");
+ case diag::MAP_WARNING:
+ OS << "warning";
+ break;
+ case diag::MAP_ERROR:
+ OS << "error";
+ break;
+ case diag::MAP_IGNORE:
+ OS << "ignored";
+ break;
+ case diag::MAP_FATAL:
+ OS << "fatal";
+ break;
+ }
+ OS << " \"" << Str << '"';
+ EmittedTokensOnThisLine = true;
+}
/// HandleFirstTokOnLine - When emitting a preprocessed file in -E mode, this
/// is called for the first token on each new line. If this really is the start
/// of a new logical line, handle it and return true, otherwise return false.
/// This may not be the start of a logical line because the "start of line"
-/// marker is set for spelling lines, not instantiation ones.
+/// marker is set for spelling lines, not expansion ones.
bool PrintPPOutputPPCallbacks::HandleFirstTokOnLine(Token &Tok) {
// Figure out what line we went to and insert the appropriate number of
// newline characters.
diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp
index 1c47bf7bee93..e49e19a17c8d 100644
--- a/lib/Frontend/TextDiagnosticPrinter.cpp
+++ b/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -292,8 +292,57 @@ static void SelectInterestingSourceRegion(std::string &SourceLine,
}
}
-void TextDiagnosticPrinter::EmitCaretDiagnostic(Diagnostic::Level Level,
- SourceLocation Loc,
+/// Look through spelling locations for a macro argument expansion, and
+/// if found skip to it so that we can trace the argument rather than the macros
+/// in which that argument is used. If no macro argument expansion is found,
+/// don't skip anything and return the starting location.
+static SourceLocation skipToMacroArgExpansion(const SourceManager &SM,
+ SourceLocation StartLoc) {
+ for (SourceLocation L = StartLoc; L.isMacroID();
+ L = SM.getImmediateSpellingLoc(L)) {
+ if (SM.isMacroArgInstantiation(L))
+ return L;
+ }
+
+ // Otherwise just return initial location, there's nothing to skip.
+ return StartLoc;
+}
+
+/// Gets the location of the immediate macro caller, one level up the stack
+/// toward the initial macro typed into the source.
+static SourceLocation getImmediateMacroCallerLoc(const SourceManager &SM,
+ SourceLocation Loc) {
+ if (!Loc.isMacroID()) return Loc;
+
+ // When we have the location of (part of) an expanded parameter, its spelling
+ // location points to the argument as typed into the macro call, and
+ // therefore is used to locate the macro caller.
+ if (SM.isMacroArgInstantiation(Loc))
+ return SM.getImmediateSpellingLoc(Loc);
+
+ // Otherwise, the caller of the macro is located where this macro is
+ // expanded (while the spelling is part of the macro definition).
+ return SM.getImmediateInstantiationRange(Loc).first;
+}
+
+/// Gets the location of the immediate macro callee, one level down the stack
+/// toward the leaf macro.
+static SourceLocation getImmediateMacroCalleeLoc(const SourceManager &SM,
+ SourceLocation Loc) {
+ if (!Loc.isMacroID()) return Loc;
+
+ // When we have the location of (part of) an expanded parameter, its
+ // expansion location points to the unexpanded paramater reference within
+ // the macro definition (or callee).
+ if (SM.isMacroArgInstantiation(Loc))
+ return SM.getImmediateInstantiationRange(Loc).first;
+
+ // Otherwise, the callee of the macro is located where this location was
+ // spelled inside the macro definition.
+ return SM.getImmediateSpellingLoc(Loc);
+}
+
+void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc,
CharSourceRange *Ranges,
unsigned NumRanges,
const SourceManager &SM,
@@ -307,38 +356,46 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(Diagnostic::Level Level,
assert(!Loc.isInvalid() && "must have a valid source location here");
// If this is a macro ID, first emit information about where this was
- // instantiated (recursively) then emit information about where the token was
+ // expanded (recursively) then emit information about where the token was
// spelled from.
if (!Loc.isFileID()) {
- // Whether to suppress printing this macro instantiation.
+ // Whether to suppress printing this macro expansion.
bool Suppressed
= OnMacroInst >= MacroSkipStart && OnMacroInst < MacroSkipEnd;
-
- SourceLocation OneLevelUp = SM.getImmediateInstantiationRange(Loc).first;
+ // When processing macros, skip over the expansions leading up to
+ // a macro argument, and trace the argument's expansion stack instead.
+ Loc = skipToMacroArgExpansion(SM, Loc);
+
+ SourceLocation OneLevelUp = getImmediateMacroCallerLoc(SM, Loc);
+
// FIXME: Map ranges?
- EmitCaretDiagnostic(Level, OneLevelUp, Ranges, NumRanges, SM, 0, 0, Columns,
+ EmitCaretDiagnostic(OneLevelUp, Ranges, NumRanges, SM,
+ Hints, NumHints, Columns,
OnMacroInst + 1, MacroSkipStart, MacroSkipEnd);
-
+
// Map the location.
- Loc = SM.getImmediateSpellingLoc(Loc);
+ Loc = getImmediateMacroCalleeLoc(SM, Loc);
// Map the ranges.
for (unsigned i = 0; i != NumRanges; ++i) {
CharSourceRange &R = Ranges[i];
SourceLocation S = R.getBegin(), E = R.getEnd();
if (S.isMacroID())
- R.setBegin(SM.getImmediateSpellingLoc(S));
+ R.setBegin(getImmediateMacroCalleeLoc(SM, S));
if (E.isMacroID())
- R.setEnd(SM.getImmediateSpellingLoc(E));
+ R.setEnd(getImmediateMacroCalleeLoc(SM, E));
}
if (!Suppressed) {
+ // Don't print recursive expansion notes from an expansion note.
+ Loc = SM.getSpellingLoc(Loc);
+
// Get the pretty name, according to #line directives etc.
PresumedLoc PLoc = SM.getPresumedLoc(Loc);
if (PLoc.isInvalid())
return;
-
+
// If this diagnostic is not in the main file, print out the
// "included from" lines.
if (LastWarningLoc != PLoc.getIncludeLoc()) {
@@ -353,9 +410,9 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(Diagnostic::Level Level,
OS << PLoc.getColumn() << ':';
OS << ' ';
}
- OS << "note: instantiated from:\n";
-
- EmitCaretDiagnostic(Level, Loc, Ranges, NumRanges, SM, Hints, NumHints,
+ OS << "note: expanded from:\n";
+
+ EmitCaretDiagnostic(Loc, Ranges, NumRanges, SM, 0, 0,
Columns, OnMacroInst + 1, MacroSkipStart,
MacroSkipEnd);
return;
@@ -364,13 +421,13 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(Diagnostic::Level Level,
if (OnMacroInst == MacroSkipStart) {
// Tell the user that we've skipped contexts.
OS << "note: (skipping " << (MacroSkipEnd - MacroSkipStart)
- << " contexts in backtrace; use -fmacro-backtrace-limit=0 to see "
+ << " expansions in backtrace; use -fmacro-backtrace-limit=0 to see "
"all)\n";
}
return;
}
-
+
// Decompose the location into a FID/Offset pair.
std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
FileID FID = LocInfo.first;
@@ -769,6 +826,20 @@ static bool PrintWordWrapped(llvm::raw_ostream &OS,
return true;
}
+/// Get the presumed location of a diagnostic message. This computes the
+/// presumed location for the top of any macro backtrace when present.
+static PresumedLoc getDiagnosticPresumedLoc(const SourceManager &SM,
+ SourceLocation Loc) {
+ // This is a condensed form of the algorithm used by EmitCaretDiagnostic to
+ // walk to the top of the macro call stack.
+ while (Loc.isMacroID()) {
+ Loc = skipToMacroArgExpansion(SM, Loc);
+ Loc = getImmediateMacroCallerLoc(SM, Loc);
+ }
+
+ return SM.getPresumedLoc(Loc);
+}
+
void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
const DiagnosticInfo &Info) {
// Default implementation (Warnings/errors count).
@@ -787,7 +858,7 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
// if enabled.
if (Info.getLocation().isValid()) {
const SourceManager &SM = Info.getSourceManager();
- PresumedLoc PLoc = SM.getPresumedLoc(Info.getLocation());
+ PresumedLoc PLoc = getDiagnosticPresumedLoc(SM, Info.getLocation());
if (PLoc.isInvalid()) {
// At least print the file name if available:
FileID FID = SM.getFileID(Info.getLocation());
@@ -1040,15 +1111,17 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
}
}
+ const SourceManager &SM = LastLoc.getManager();
unsigned MacroInstSkipStart = 0, MacroInstSkipEnd = 0;
if (DiagOpts && DiagOpts->MacroBacktraceLimit && !LastLoc.isFileID()) {
- // Compute the length of the macro-instantiation backtrace, so that we
+ // Compute the length of the macro-expansion backtrace, so that we
// can establish which steps in the macro backtrace we'll skip.
SourceLocation Loc = LastLoc;
unsigned Depth = 0;
do {
++Depth;
- Loc = LastLoc.getManager().getImmediateInstantiationRange(Loc).first;
+ Loc = skipToMacroArgExpansion(SM, Loc);
+ Loc = getImmediateMacroCallerLoc(SM, Loc);
} while (!Loc.isFileID());
if (Depth > DiagOpts->MacroBacktraceLimit) {
@@ -1058,7 +1131,7 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
}
}
- EmitCaretDiagnostic(Level, LastLoc, Ranges, NumRanges, LastLoc.getManager(),
+ EmitCaretDiagnostic(LastLoc, Ranges, NumRanges, LastLoc.getManager(),
Info.getFixItHints(),
Info.getNumFixItHints(),
DiagOpts->MessageLength,
diff --git a/lib/FrontendTool/CMakeLists.txt b/lib/FrontendTool/CMakeLists.txt
index 720ce2adf123..b8e4329c07f9 100644
--- a/lib/FrontendTool/CMakeLists.txt
+++ b/lib/FrontendTool/CMakeLists.txt
@@ -1,5 +1,6 @@
set(LLVM_USED_LIBS clangDriver clangFrontend clangRewrite clangCodeGen
- clangStaticAnalyzerFrontend clangStaticAnalyzerCheckers clangStaticAnalyzerCore)
+ clangStaticAnalyzerFrontend clangStaticAnalyzerCheckers clangStaticAnalyzerCore
+ clangARCMigrate)
add_clang_library(clangFrontendTool
ExecuteCompilerInvocation.cpp
diff --git a/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index 664b53351dc1..f2db3ae74191 100644
--- a/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -14,6 +14,7 @@
#include "clang/FrontendTool/Utils.h"
#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
+#include "clang/ARCMigrate/ARCMTActions.h"
#include "clang/CodeGen/CodeGenAction.h"
#include "clang/Driver/CC1Options.h"
#include "clang/Driver/OptTable.h"
@@ -38,7 +39,6 @@ static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) {
case ASTDumpXML: return new ASTDumpXMLAction();
case ASTPrint: return new ASTPrintAction();
case ASTView: return new ASTViewAction();
- case BoostCon: return new BoostConAction();
case CreateModule: return 0;
case DumpRawTokens: return new DumpRawTokensAction();
case DumpTokens: return new DumpTokensAction();
@@ -89,6 +89,21 @@ static FrontendAction *CreateFrontendAction(CompilerInstance &CI) {
if (!Act)
return 0;
+ // Potentially wrap the base FE action in an ARC Migrate Tool action.
+ switch (CI.getFrontendOpts().ARCMTAction) {
+ case FrontendOptions::ARCMT_None:
+ break;
+ case FrontendOptions::ARCMT_Check:
+ Act = new arcmt::CheckAction(Act);
+ break;
+ case FrontendOptions::ARCMT_Modify:
+ Act = new arcmt::ModifyAction(Act);
+ break;
+ case FrontendOptions::ARCMT_Migrate:
+ Act = new arcmt::MigrateAction(Act, CI.getFrontendOpts().ARCMTMigrateDir);
+ break;
+ }
+
// If there are any AST files to merge, create a frontend action
// adaptor to perform the merge.
if (!CI.getFrontendOpts().ASTMergeFiles.empty())
diff --git a/lib/Headers/float.h b/lib/Headers/float.h
index 28fb882bd24a..6eede0b6ba47 100644
--- a/lib/Headers/float.h
+++ b/lib/Headers/float.h
@@ -24,6 +24,48 @@
#ifndef __FLOAT_H
#define __FLOAT_H
+/* If we're on MinGW, fall baack to the system's float.h, which might have
+ * additional definitions provided for Windows.
+ * For more details see http://msdn.microsoft.com/en-us/library/y0ybw9fy.aspx
+ */
+#if defined(__MINGW32__) && \
+ defined(__has_include_next) && __has_include_next(<float.h>)
+# include_next <float.h>
+
+/* Undefine anything that we'll be redefining below. */
+# undef FLT_EVAL_METHOD
+# undef FLT_ROUNDS
+# undef FLT_RADIX
+# undef FLT_MANT_DIG
+# undef DBL_MANT_DIG
+# undef LDBL_MANT_DIG
+# undef DECIMAL_DIG
+# undef FLT_DIG
+# undef DBL_DIG
+# undef LDBL_DIG
+# undef FLT_MIN_EXP
+# undef DBL_MIN_EXP
+# undef LDBL_MIN_EXP
+# undef FLT_MIN_10_EXP
+# undef DBL_MIN_10_EXP
+# undef LDBL_MIN_10_EXP
+# undef FLT_MAX_EXP
+# undef DBL_MAX_EXP
+# undef LDBL_MAX_EXP
+# undef FLT_MAX_10_EXP
+# undef DBL_MAX_10_EXP
+# undef LDBL_MAX_10_EXP
+# undef FLT_MAX
+# undef DBL_MAX
+# undef LDBL_MAX
+# undef FLT_EPSILON
+# undef DBL_EPSILON
+# undef LDBL_EPSILON
+# undef FLT_MIN
+# undef DBL_MIN
+# undef LDBL_MIN
+#endif
+
/* Characteristics of floating point types, C99 5.2.4.2.2 */
#define FLT_EVAL_METHOD __FLT_EVAL_METHOD__
diff --git a/lib/Headers/stdarg.h b/lib/Headers/stdarg.h
index c36ab12019fe..2957bf058ea8 100644
--- a/lib/Headers/stdarg.h
+++ b/lib/Headers/stdarg.h
@@ -39,7 +39,7 @@ typedef __builtin_va_list va_list;
*/
#define __va_copy(d,s) __builtin_va_copy(d,s)
-#if __STDC_VERSION__ >= 199900L || !defined(__STRICT_ANSI__)
+#if __STDC_VERSION__ >= 199900L || __cplusplus >= 201103L || !defined(__STRICT_ANSI__)
#define va_copy(dest, src) __builtin_va_copy(dest, src)
#endif
diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp
index bb4388195a32..86ab9564a235 100644
--- a/lib/Lex/HeaderSearch.cpp
+++ b/lib/Lex/HeaderSearch.cpp
@@ -123,10 +123,8 @@ const FileEntry *DirectoryLookup::LookupFile(
llvm::SmallString<1024> TmpDir;
if (isNormalDir()) {
// Concatenate the requested file onto the directory.
- // FIXME: Portability. Filename concatenation should be in sys::Path.
- TmpDir += getDir()->getName();
- TmpDir.push_back('/');
- TmpDir.append(Filename.begin(), Filename.end());
+ TmpDir = getDir()->getName();
+ llvm::sys::path::append(TmpDir, Filename);
if (SearchPath != NULL) {
llvm::StringRef SearchPathRef(getDir()->getName());
SearchPath->clear();
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index 3b1149c08af3..a28b8f6e7b9f 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -156,7 +156,7 @@ Lexer::Lexer(FileID FID, const llvm::MemoryBuffer *FromFile,
///
/// On entrance to this routine, TokStartLoc is a macro location which has a
/// spelling loc that indicates the bytes to be lexed for the token and an
-/// instantiation location that indicates where all lexed tokens should be
+/// expansion location that indicates where all lexed tokens should be
/// "expanded from".
///
/// FIXME: It would really be nice to make _Pragma just be a wrapper around a
@@ -166,8 +166,8 @@ Lexer::Lexer(FileID FID, const llvm::MemoryBuffer *FromFile,
/// out of the critical path of the lexer!
///
Lexer *Lexer::Create_PragmaLexer(SourceLocation SpellingLoc,
- SourceLocation InstantiationLocStart,
- SourceLocation InstantiationLocEnd,
+ SourceLocation ExpansionLocStart,
+ SourceLocation ExpansionLocEnd,
unsigned TokLen, Preprocessor &PP) {
SourceManager &SM = PP.getSourceManager();
@@ -188,8 +188,8 @@ Lexer *Lexer::Create_PragmaLexer(SourceLocation SpellingLoc,
// Set the SourceLocation with the remapping information. This ensures that
// GetMappedTokenLoc will remap the tokens as they are lexed.
L->FileLoc = SM.createInstantiationLoc(SM.getLocForStartOfFile(SpellingFID),
- InstantiationLocStart,
- InstantiationLocEnd, TokLen);
+ ExpansionLocStart,
+ ExpansionLocEnd, TokLen);
// Ensure that the lexer thinks it is inside a directive, so that end \n will
// return an EOD token.
@@ -621,7 +621,7 @@ SourceLocation Lexer::AdvanceToTokenCharacter(SourceLocation TokStart,
unsigned CharNo,
const SourceManager &SM,
const LangOptions &Features) {
- // Figure out how many physical characters away the specified instantiation
+ // Figure out how many physical characters away the specified expansion
// character is. This needs to take into consideration newlines and
// trigraphs.
bool Invalid = false;
@@ -679,9 +679,17 @@ SourceLocation Lexer::AdvanceToTokenCharacter(SourceLocation TokStart,
SourceLocation Lexer::getLocForEndOfToken(SourceLocation Loc, unsigned Offset,
const SourceManager &SM,
const LangOptions &Features) {
- if (Loc.isInvalid() || !Loc.isFileID())
+ if (Loc.isInvalid())
return SourceLocation();
-
+
+ if (Loc.isMacroID()) {
+ if (Offset > 0 || !isAtEndOfMacroExpansion(Loc, SM, Features))
+ return SourceLocation(); // Points inside the macro expansion.
+
+ // Continue and find the location just after the macro expansion.
+ Loc = SM.getInstantiationRange(Loc).second;
+ }
+
unsigned Len = Lexer::MeasureTokenLength(Loc, SM, Features);
if (Len > Offset)
Len = Len - Offset;
@@ -691,6 +699,58 @@ SourceLocation Lexer::getLocForEndOfToken(SourceLocation Loc, unsigned Offset,
return Loc.getFileLocWithOffset(Len);
}
+/// \brief Returns true if the given MacroID location points at the first
+/// token of the macro expansion.
+bool Lexer::isAtStartOfMacroExpansion(SourceLocation loc,
+ const SourceManager &SM,
+ const LangOptions &LangOpts) {
+ assert(loc.isValid() && loc.isMacroID() && "Expected a valid macro loc");
+
+ std::pair<FileID, unsigned> infoLoc = SM.getDecomposedLoc(loc);
+ // FIXME: If the token comes from the macro token paste operator ('##')
+ // this function will always return false;
+ if (infoLoc.second > 0)
+ return false; // Does not point at the start of token.
+
+ SourceLocation expansionLoc =
+ SM.getSLocEntry(infoLoc.first)
+ .getInstantiation().getInstantiationLocStart();
+ if (expansionLoc.isFileID())
+ return true; // No other macro expansions, this is the first.
+
+ return isAtStartOfMacroExpansion(expansionLoc, SM, LangOpts);
+}
+
+/// \brief Returns true if the given MacroID location points at the last
+/// token of the macro expansion.
+bool Lexer::isAtEndOfMacroExpansion(SourceLocation loc,
+ const SourceManager &SM,
+ const LangOptions &LangOpts) {
+ assert(loc.isValid() && loc.isMacroID() && "Expected a valid macro loc");
+
+ SourceLocation spellLoc = SM.getSpellingLoc(loc);
+ unsigned tokLen = MeasureTokenLength(spellLoc, SM, LangOpts);
+ if (tokLen == 0)
+ return false;
+
+ FileID FID = SM.getFileID(loc);
+ SourceLocation afterLoc = loc.getFileLocWithOffset(tokLen+1);
+ if (!SM.isBeforeInSourceLocationOffset(afterLoc, SM.getNextOffset()))
+ return true; // We got past the last FileID, this points to the last token.
+
+ // FIXME: If the token comes from the macro token paste operator ('##')
+ // or the stringify operator ('#') this function will always return false;
+ if (FID == SM.getFileID(afterLoc))
+ return false; // Still in the same FileID, does not point to the last token.
+
+ SourceLocation expansionLoc =
+ SM.getSLocEntry(FID).getInstantiation().getInstantiationLocEnd();
+ if (expansionLoc.isFileID())
+ return true; // No other macro expansions.
+
+ return isAtEndOfMacroExpansion(expansionLoc, SM, LangOpts);
+}
+
//===----------------------------------------------------------------------===//
// Character information.
//===----------------------------------------------------------------------===//
@@ -829,7 +889,7 @@ static inline bool isNumberBody(unsigned char c) {
//===----------------------------------------------------------------------===//
/// GetMappedTokenLoc - If lexing out of a 'mapped buffer', where we pretend the
-/// lexer buffer was all instantiated at a single point, perform the mapping.
+/// lexer buffer was all expanded at a single point, perform the mapping.
/// This is currently only used for _Pragma implementation, so it is the slow
/// path of the hot getSourceLocation method. Do not allow it to be inlined.
static LLVM_ATTRIBUTE_NOINLINE SourceLocation GetMappedTokenLoc(
@@ -837,14 +897,14 @@ static LLVM_ATTRIBUTE_NOINLINE SourceLocation GetMappedTokenLoc(
static SourceLocation GetMappedTokenLoc(Preprocessor &PP,
SourceLocation FileLoc,
unsigned CharNo, unsigned TokLen) {
- assert(FileLoc.isMacroID() && "Must be an instantiation");
+ assert(FileLoc.isMacroID() && "Must be a macro expansion");
// Otherwise, we're lexing "mapped tokens". This is used for things like
- // _Pragma handling. Combine the instantiation location of FileLoc with the
+ // _Pragma handling. Combine the expansion location of FileLoc with the
// spelling location.
SourceManager &SM = PP.getSourceManager();
- // Create a new SLoc which is expanded from Instantiation(FileLoc) but whose
+ // Create a new SLoc which is expanded from Expansion(FileLoc) but whose
// characters come from spelling(FileLoc)+Offset.
SourceLocation SpellingLoc = SM.getSpellingLoc(FileLoc);
SpellingLoc = SpellingLoc.getFileLocWithOffset(CharNo);
diff --git a/lib/Lex/MacroArgs.cpp b/lib/Lex/MacroArgs.cpp
index dee7da38aaa0..968c15e3c27b 100644
--- a/lib/Lex/MacroArgs.cpp
+++ b/lib/Lex/MacroArgs.cpp
@@ -185,7 +185,8 @@ MacroArgs::getPreExpArgument(unsigned Arg, const MacroInfo *MI,
/// a character literal for the Microsoft charize (#@) extension.
///
Token MacroArgs::StringifyArgument(const Token *ArgToks,
- Preprocessor &PP, bool Charify) {
+ Preprocessor &PP, bool Charify,
+ SourceLocation hashInstLoc) {
Token Tok;
Tok.startToken();
Tok.setKind(Charify ? tok::char_constant : tok::string_literal);
@@ -273,14 +274,15 @@ Token MacroArgs::StringifyArgument(const Token *ArgToks,
}
}
- PP.CreateString(&Result[0], Result.size(), Tok);
+ PP.CreateString(&Result[0], Result.size(), Tok, hashInstLoc);
return Tok;
}
/// getStringifiedArgument - Compute, cache, and return the specified argument
/// that has been 'stringified' as required by the # operator.
const Token &MacroArgs::getStringifiedArgument(unsigned ArgNo,
- Preprocessor &PP) {
+ Preprocessor &PP,
+ SourceLocation hashInstLoc) {
assert(ArgNo < NumUnexpArgTokens && "Invalid argument number!");
if (StringifiedArgs.empty()) {
StringifiedArgs.resize(getNumArguments());
@@ -288,6 +290,7 @@ const Token &MacroArgs::getStringifiedArgument(unsigned ArgNo,
sizeof(StringifiedArgs[0])*getNumArguments());
}
if (StringifiedArgs[ArgNo].isNot(tok::string_literal))
- StringifiedArgs[ArgNo] = StringifyArgument(getUnexpArgument(ArgNo), PP);
+ StringifiedArgs[ArgNo] = StringifyArgument(getUnexpArgument(ArgNo), PP,
+ /*Charify=*/false, hashInstLoc);
return StringifiedArgs[ArgNo];
}
diff --git a/lib/Lex/MacroArgs.h b/lib/Lex/MacroArgs.h
index 6ff4856b4e1c..a962dacf7c93 100644
--- a/lib/Lex/MacroArgs.h
+++ b/lib/Lex/MacroArgs.h
@@ -20,6 +20,7 @@ namespace clang {
class MacroInfo;
class Preprocessor;
class Token;
+ class SourceLocation;
/// MacroArgs - An instance of this class captures information about
/// the formal arguments specified to a function-like macro invocation.
@@ -86,7 +87,8 @@ public:
/// getStringifiedArgument - Compute, cache, and return the specified argument
/// that has been 'stringified' as required by the # operator.
- const Token &getStringifiedArgument(unsigned ArgNo, Preprocessor &PP);
+ const Token &getStringifiedArgument(unsigned ArgNo, Preprocessor &PP,
+ SourceLocation hashInstLoc);
/// getNumArguments - Return the number of arguments passed into this macro
/// invocation.
@@ -106,7 +108,8 @@ public:
/// a character literal for the Microsoft charize (#@) extension.
///
static Token StringifyArgument(const Token *ArgToks,
- Preprocessor &PP, bool Charify = false);
+ Preprocessor &PP, bool Charify,
+ SourceLocation hashInstLoc);
/// deallocate - This should only be called by the Preprocessor when managing
diff --git a/lib/Lex/MacroInfo.cpp b/lib/Lex/MacroInfo.cpp
index 66d87a19386a..0a16a2567219 100644
--- a/lib/Lex/MacroInfo.cpp
+++ b/lib/Lex/MacroInfo.cpp
@@ -25,6 +25,7 @@ MacroInfo::MacroInfo(SourceLocation DefLoc) : Location(DefLoc) {
IsUsed = false;
IsAllowRedefinitionsWithoutWarning = false;
IsWarnIfUnused = false;
+ IsDefinitionLengthCached = false;
ArgumentList = 0;
NumArguments = 0;
@@ -43,11 +44,42 @@ MacroInfo::MacroInfo(const MacroInfo &MI, llvm::BumpPtrAllocator &PPAllocator) {
IsUsed = MI.IsUsed;
IsAllowRedefinitionsWithoutWarning = MI.IsAllowRedefinitionsWithoutWarning;
IsWarnIfUnused = MI.IsWarnIfUnused;
+ IsDefinitionLengthCached = MI.IsDefinitionLengthCached;
+ DefinitionLength = MI.DefinitionLength;
ArgumentList = 0;
NumArguments = 0;
setArgumentList(MI.ArgumentList, MI.NumArguments, PPAllocator);
}
+unsigned MacroInfo::getDefinitionLengthSlow(SourceManager &SM) const {
+ assert(!IsDefinitionLengthCached);
+ IsDefinitionLengthCached = true;
+
+ if (ReplacementTokens.empty())
+ return (DefinitionLength = 0);
+
+ const Token &firstToken = ReplacementTokens.front();
+ const Token &lastToken = ReplacementTokens.back();
+ SourceLocation macroStart = firstToken.getLocation();
+ SourceLocation macroEnd = lastToken.getLocation();
+ assert(macroStart.isValid() && macroEnd.isValid());
+ assert((macroStart.isFileID() || firstToken.is(tok::comment)) &&
+ "Macro defined in macro?");
+ assert((macroEnd.isFileID() || lastToken.is(tok::comment)) &&
+ "Macro defined in macro?");
+ std::pair<FileID, unsigned>
+ startInfo = SM.getDecomposedInstantiationLoc(macroStart);
+ std::pair<FileID, unsigned>
+ endInfo = SM.getDecomposedInstantiationLoc(macroEnd);
+ assert(startInfo.first == endInfo.first &&
+ "Macro definition spanning multiple FileIDs ?");
+ assert(startInfo.second <= endInfo.second);
+ DefinitionLength = endInfo.second - startInfo.second;
+ DefinitionLength += lastToken.getLength();
+
+ return DefinitionLength;
+}
+
/// isIdenticalTo - Return true if the specified macro definition is equal to
/// this macro in spelling, arguments, and whitespace. This is used to emit
/// duplicate definition warnings. This implements the rules in C99 6.10.3.
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index 66e44bbc6dd0..4af5fabe5c80 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -784,8 +784,7 @@ void Preprocessor::HandleLineDirective(Token &Tok) {
Diag(StrTok, diag::err_pp_linemarker_invalid_filename);
return DiscardUntilEndOfDirective();
}
- FilenameID = SourceMgr.getLineTableFilenameID(Literal.GetString(),
- Literal.GetStringLength());
+ FilenameID = SourceMgr.getLineTableFilenameID(Literal.GetString());
// Verify that there is nothing after the string, other than EOD. Because
// of C99 6.10.4p5, macros that expand to empty tokens are ok.
@@ -918,8 +917,7 @@ void Preprocessor::HandleDigitDirective(Token &DigitTok) {
Diag(StrTok, diag::err_pp_linemarker_invalid_filename);
return DiscardUntilEndOfDirective();
}
- FilenameID = SourceMgr.getLineTableFilenameID(Literal.GetString(),
- Literal.GetStringLength());
+ FilenameID = SourceMgr.getLineTableFilenameID(Literal.GetString());
// If a filename was present, read any flags that are present.
if (ReadLineMarkerFlags(IsFileEntry, IsFileExit,
@@ -1182,16 +1180,17 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
const FileEntry *File = LookupFile(
Filename, isAngled, LookupFrom, CurDir,
Callbacks ? &SearchPath : NULL, Callbacks ? &RelativePath : NULL);
- if (File == 0) {
- Diag(FilenameTok, diag::err_pp_file_not_found) << Filename;
- return;
- }
// Notify the callback object that we've seen an inclusion directive.
if (Callbacks)
Callbacks->InclusionDirective(HashLoc, IncludeTok, Filename, isAngled, File,
End, SearchPath, RelativePath);
+ if (File == 0) {
+ Diag(FilenameTok, diag::warn_pp_file_not_found) << Filename;
+ return;
+ }
+
// The #included file will be considered to be a system header if either it is
// in a system include directory, or if the #includer is a system include
// header.
@@ -1210,10 +1209,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
// Look up the file, create a File ID for it.
FileID FID = SourceMgr.createFileID(File, FilenameTok.getLocation(),
FileCharacter);
- if (FID.isInvalid()) {
- Diag(FilenameTok, diag::err_pp_file_not_found) << Filename;
- return;
- }
+ assert(!FID.isInvalid() && "Expected valid file ID");
// Finally, if all is good, enter the new file!
EnterSourceFile(FID, CurDir, FilenameTok.getLocation());
@@ -1599,7 +1595,7 @@ void Preprocessor::HandleUndefDirective(Token &UndefTok) {
// If the macro is not defined, this is a noop undef, just return.
if (MI == 0) return;
- if (!MI->isUsed())
+ if (!MI->isUsed() && MI->isWarnIfUnused())
Diag(MI->getDefinitionLoc(), diag::pp_macro_not_used);
// If the callbacks want to know, tell them about the macro #undef.
diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp
index bf0a7fbfef18..bf28199b888a 100644
--- a/lib/Lex/PPLexerChange.cpp
+++ b/lib/Lex/PPLexerChange.cpp
@@ -265,6 +265,10 @@ bool Preprocessor::HandleEndOfTokenLexer(Token &Result) {
assert(CurTokenLexer && !CurPPLexer &&
"Ending a macro when currently in a #include file!");
+ if (!MacroExpandingLexersStack.empty() &&
+ MacroExpandingLexersStack.back().first == CurTokenLexer.get())
+ removeCachedMacroExpandedTokensOfLastLexer();
+
// Delete or cache the now-dead macro expander.
if (NumCachedTokenLexers == TokenLexerCacheSize)
CurTokenLexer.reset();
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index 01cd75fa8485..ecd4d4cfc68b 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -22,6 +22,7 @@
#include "clang/Lex/CodeCompletionHandler.h"
#include "clang/Lex/ExternalPreprocessorSource.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Config/config.h"
#include "llvm/Support/raw_ostream.h"
#include <cstdio>
@@ -194,9 +195,9 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
/// invocation.
MacroArgs *Args = 0;
- // Remember where the end of the instantiation occurred. For an object-like
+ // Remember where the end of the expansion occurred. For an object-like
// macro, this is the identifier. For a function-like macro, this is the ')'.
- SourceLocation InstantiationEnd = Identifier.getLocation();
+ SourceLocation ExpansionEnd = Identifier.getLocation();
// If this is a function-like macro, read the arguments.
if (MI->isFunctionLike()) {
@@ -209,7 +210,7 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
// Preprocessor directives used inside macro arguments are not portable, and
// this enables the warning.
InMacroArgs = true;
- Args = ReadFunctionLikeMacroArgs(Identifier, MI, InstantiationEnd);
+ Args = ReadFunctionLikeMacroArgs(Identifier, MI, ExpansionEnd);
// Finished parsing args.
InMacroArgs = false;
@@ -229,8 +230,8 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
// If we started lexing a macro, enter the macro expansion body.
- // Remember where the token is instantiated.
- SourceLocation InstantiateLoc = Identifier.getLocation();
+ // Remember where the token is expanded.
+ SourceLocation ExpandLoc = Identifier.getLocation();
// If this macro expands to no tokens, don't bother to push it onto the
// expansion stack, only to take it right back off.
@@ -254,7 +255,7 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
if (HadLeadingSpace) Identifier.setFlag(Token::LeadingSpace);
}
Identifier.setFlag(Token::LeadingEmptyMacro);
- LastEmptyMacroInstantiationLoc = InstantiateLoc;
+ LastEmptyMacroExpansionLoc = ExpandLoc;
++NumFastMacroExpanded;
return false;
@@ -280,11 +281,11 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
Identifier.setFlagValue(Token::StartOfLine , isAtStartOfLine);
Identifier.setFlagValue(Token::LeadingSpace, hasLeadingSpace);
- // Update the tokens location to include both its instantiation and physical
+ // Update the tokens location to include both its expansion and physical
// locations.
SourceLocation Loc =
- SourceMgr.createInstantiationLoc(Identifier.getLocation(), InstantiateLoc,
- InstantiationEnd,Identifier.getLength());
+ SourceMgr.createInstantiationLoc(Identifier.getLocation(), ExpandLoc,
+ ExpansionEnd,Identifier.getLength());
Identifier.setLocation(Loc);
// If this is a disabled macro or #define X X, we must mark the result as
@@ -302,7 +303,7 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
}
// Start expanding the macro.
- EnterMacro(Identifier, InstantiationEnd, Args);
+ EnterMacro(Identifier, ExpansionEnd, Args);
// Now that the macro is at the top of the include stack, ask the
// preprocessor to read the next token from it.
@@ -490,6 +491,46 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
isVarargsElided, *this);
}
+/// \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.
+Token *Preprocessor::cacheMacroExpandedTokens(TokenLexer *tokLexer,
+ llvm::ArrayRef<Token> tokens) {
+ assert(tokLexer);
+ if (tokens.empty())
+ return 0;
+
+ size_t newIndex = MacroExpandedTokens.size();
+ bool cacheNeedsToGrow = tokens.size() >
+ MacroExpandedTokens.capacity()-MacroExpandedTokens.size();
+ MacroExpandedTokens.append(tokens.begin(), tokens.end());
+
+ if (cacheNeedsToGrow) {
+ // Go through all the TokenLexers whose 'Tokens' pointer points in the
+ // buffer and update the pointers to the (potential) new buffer array.
+ for (unsigned i = 0, e = MacroExpandingLexersStack.size(); i != e; ++i) {
+ TokenLexer *prevLexer;
+ size_t tokIndex;
+ llvm::tie(prevLexer, tokIndex) = MacroExpandingLexersStack[i];
+ prevLexer->Tokens = MacroExpandedTokens.data() + tokIndex;
+ }
+ }
+
+ MacroExpandingLexersStack.push_back(std::make_pair(tokLexer, newIndex));
+ return MacroExpandedTokens.data() + newIndex;
+}
+
+void Preprocessor::removeCachedMacroExpandedTokensOfLastLexer() {
+ assert(!MacroExpandingLexersStack.empty());
+ size_t tokIndex = MacroExpandingLexersStack.back().second;
+ assert(tokIndex < MacroExpandedTokens.size());
+ // Pop the cached macro expanded tokens from the end.
+ MacroExpandedTokens.resize(tokIndex);
+ MacroExpandingLexersStack.pop_back();
+}
+
/// ComputeDATE_TIME - Compute the current time, enter it into the specified
/// scratch buffer, then return DATELoc/TIMELoc locations with the position of
/// the identifier tokens inserted.
@@ -551,6 +592,11 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
.Case("cxx_exceptions", LangOpts.Exceptions)
.Case("cxx_rtti", LangOpts.RTTI)
.Case("enumerator_attributes", true)
+ // Objective-C features
+ .Case("objc_arr", LangOpts.ObjCAutoRefCount) // FIXME: REMOVE?
+ .Case("objc_arc", LangOpts.ObjCAutoRefCount)
+ .Case("objc_arc_weak", LangOpts.ObjCAutoRefCount &&
+ LangOpts.ObjCRuntimeHasWeak)
.Case("objc_nonfragile_abi", LangOpts.ObjCNonFragileABI)
.Case("objc_weak_class", LangOpts.ObjCNonFragileABI)
.Case("ownership_holds", true)
@@ -787,10 +833,10 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
Loc = AdvanceToTokenCharacter(Loc, 0);
// One wrinkle here is that GCC expands __LINE__ to location of the *end* of
- // a macro instantiation. This doesn't matter for object-like macros, but
+ // a macro expansion. This doesn't matter for object-like macros, but
// can matter for a function-like macro that expands to contain __LINE__.
- // Skip down through instantiation points until we find a file loc for the
- // end of the instantiation history.
+ // Skip down through expansion points until we find a file loc for the
+ // end of the expansion history.
Loc = SourceMgr.getInstantiationRange(Loc).second;
PresumedLoc PLoc = SourceMgr.getPresumedLoc(Loc);
diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp
index 23855d4a4748..e6b28c13317b 100644
--- a/lib/Lex/Pragma.cpp
+++ b/lib/Lex/Pragma.cpp
@@ -326,9 +326,7 @@ void Preprocessor::HandlePragmaSystemHeader(Token &SysHeaderTok) {
if (PLoc.isInvalid())
return;
- unsigned FilenameLen = strlen(PLoc.getFilename());
- unsigned FilenameID = SourceMgr.getLineTableFilenameID(PLoc.getFilename(),
- FilenameLen);
+ unsigned FilenameID = SourceMgr.getLineTableFilenameID(PLoc.getFilename());
// Notify the client, if desired, that we are in a new source file.
if (Callbacks)
@@ -370,7 +368,7 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) {
const DirectoryLookup *CurDir;
const FileEntry *File = LookupFile(Filename, isAngled, 0, CurDir, NULL, NULL);
if (File == 0) {
- Diag(FilenameTok, diag::err_pp_file_not_found) << Filename;
+ Diag(FilenameTok, diag::warn_pp_file_not_found) << Filename;
return;
}
@@ -454,8 +452,7 @@ void Preprocessor::HandlePragmaComment(Token &Tok) {
return;
}
- ArgumentString = std::string(Literal.GetString(),
- Literal.GetString()+Literal.GetStringLength());
+ ArgumentString = Literal.GetString();
}
// FIXME: If the kind is "compiler" warn if the string is present (it is
@@ -531,7 +528,7 @@ void Preprocessor::HandlePragmaMessage(Token &Tok) {
return;
}
- llvm::StringRef MessageString(Literal.GetString(), Literal.GetStringLength());
+ llvm::StringRef MessageString(Literal.GetString());
if (ExpectClosingParen) {
if (Tok.isNot(tok::r_paren)) {
@@ -839,8 +836,11 @@ struct PragmaDebugHandler : public PragmaHandler {
/// PragmaDiagnosticHandler - e.g. '#pragma GCC diagnostic ignored "-Wformat"'
struct PragmaDiagnosticHandler : public PragmaHandler {
+private:
+ const char *Namespace;
public:
- explicit PragmaDiagnosticHandler() : PragmaHandler("diagnostic") {}
+ explicit PragmaDiagnosticHandler(const char *NS) :
+ PragmaHandler("diagnostic"), Namespace(NS) {}
virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &DiagToken) {
SourceLocation DiagLoc = DiagToken.getLocation();
@@ -851,6 +851,7 @@ public:
return;
}
IdentifierInfo *II = Tok.getIdentifierInfo();
+ PPCallbacks *Callbacks = PP.getPPCallbacks();
diag::Mapping Map;
if (II->isStr("warning"))
@@ -864,10 +865,13 @@ public:
else if (II->isStr("pop")) {
if (!PP.getDiagnostics().popMappings(DiagLoc))
PP.Diag(Tok, diag::warn_pragma_diagnostic_cannot_pop);
-
+ else if (Callbacks)
+ Callbacks->PragmaDiagnosticPop(DiagLoc, Namespace);
return;
} else if (II->isStr("push")) {
PP.getDiagnostics().pushMappings(DiagLoc);
+ if (Callbacks)
+ Callbacks->PragmaDiagnosticPush(DiagLoc, Namespace);
return;
} else {
PP.Diag(Tok, diag::warn_pragma_diagnostic_invalid);
@@ -906,7 +910,7 @@ public:
return;
}
- llvm::StringRef WarningName(Literal.GetString(), Literal.GetStringLength());
+ llvm::StringRef WarningName(Literal.GetString());
if (WarningName.size() < 3 || WarningName[0] != '-' ||
WarningName[1] != 'W') {
@@ -919,6 +923,8 @@ public:
Map, DiagLoc))
PP.Diag(StrToks[0].getLocation(),
diag::warn_pragma_diagnostic_unknown_warning) << WarningName;
+ else if (Callbacks)
+ Callbacks->PragmaDiagnostic(DiagLoc, Namespace, Map, WarningName);
}
};
@@ -1013,13 +1019,13 @@ void Preprocessor::RegisterBuiltinPragmas() {
AddPragmaHandler("GCC", new PragmaPoisonHandler());
AddPragmaHandler("GCC", new PragmaSystemHeaderHandler());
AddPragmaHandler("GCC", new PragmaDependencyHandler());
- AddPragmaHandler("GCC", new PragmaDiagnosticHandler());
+ AddPragmaHandler("GCC", new PragmaDiagnosticHandler("GCC"));
// #pragma clang ...
AddPragmaHandler("clang", new PragmaPoisonHandler());
AddPragmaHandler("clang", new PragmaSystemHeaderHandler());
AddPragmaHandler("clang", new PragmaDebugHandler());
AddPragmaHandler("clang", new PragmaDependencyHandler());
- AddPragmaHandler("clang", new PragmaDiagnosticHandler());
+ AddPragmaHandler("clang", new PragmaDiagnosticHandler("clang"));
AddPragmaHandler("STDC", new PragmaSTDC_FENV_ACCESSHandler());
AddPragmaHandler("STDC", new PragmaSTDC_CX_LIMITED_RANGEHandler());
diff --git a/lib/Lex/PreprocessingRecord.cpp b/lib/Lex/PreprocessingRecord.cpp
index 0c8d948ce0a7..9f93ab04502a 100644
--- a/lib/Lex/PreprocessingRecord.cpp
+++ b/lib/Lex/PreprocessingRecord.cpp
@@ -45,8 +45,8 @@ void PreprocessingRecord::MaybeLoadPreallocatedEntities() const {
ExternalSource->ReadPreprocessedEntities();
}
-PreprocessingRecord::PreprocessingRecord(bool IncludeNestedMacroInstantiations)
- : IncludeNestedMacroInstantiations(IncludeNestedMacroInstantiations),
+PreprocessingRecord::PreprocessingRecord(bool IncludeNestedMacroExpansions)
+ : IncludeNestedMacroExpansions(IncludeNestedMacroExpansions),
ExternalSource(0), NumPreallocatedEntities(0),
LoadedPreallocatedEntities(false)
{
@@ -121,14 +121,13 @@ MacroDefinition *PreprocessingRecord::findMacroDefinition(const MacroInfo *MI) {
}
void PreprocessingRecord::MacroExpands(const Token &Id, const MacroInfo* MI) {
- if (!IncludeNestedMacroInstantiations && Id.getLocation().isMacroID())
+ if (!IncludeNestedMacroExpansions && Id.getLocation().isMacroID())
return;
if (MacroDefinition *Def = findMacroDefinition(MI))
PreprocessedEntities.push_back(
- new (*this) MacroInstantiation(Id.getIdentifierInfo(),
- Id.getLocation(),
- Def));
+ new (*this) MacroExpansion(Id.getIdentifierInfo(),
+ Id.getLocation(), Def));
}
void PreprocessingRecord::MacroDefined(const Token &Id,
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
index fdc18f878180..e7aa286a16bf 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -118,6 +118,8 @@ Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts,
Preprocessor::~Preprocessor() {
assert(BacktrackPositions.empty() && "EnableBacktrack/Backtrack imbalance!");
+ assert(MacroExpandingLexersStack.empty() && MacroExpandedTokens.empty() &&
+ "Preprocessor::HandleEndOfTokenLexer should have cleared those");
while (!IncludeMacroStack.empty()) {
delete IncludeMacroStack.back().TheLexer;
@@ -225,6 +227,10 @@ Preprocessor::macro_begin(bool IncludeExternalMacros) const {
return Macros.begin();
}
+size_t Preprocessor::getTotalMemory() const {
+ return BP.getTotalMemory() + MacroExpandedTokens.capacity()*sizeof(Token);
+}
+
Preprocessor::macro_iterator
Preprocessor::macro_end(bool IncludeExternalMacros) const {
if (IncludeExternalMacros && ExternalSource &&
@@ -322,15 +328,15 @@ llvm::StringRef Preprocessor::getSpelling(const Token &Tok,
/// location for it. If specified, the source location provides a source
/// location for the token.
void Preprocessor::CreateString(const char *Buf, unsigned Len, Token &Tok,
- SourceLocation InstantiationLoc) {
+ SourceLocation ExpansionLoc) {
Tok.setLength(Len);
const char *DestPtr;
SourceLocation Loc = ScratchBuf->getToken(Buf, Len, DestPtr);
- if (InstantiationLoc.isValid())
- Loc = SourceMgr.createInstantiationLoc(Loc, InstantiationLoc,
- InstantiationLoc, Len);
+ if (ExpansionLoc.isValid())
+ Loc = SourceMgr.createInstantiationLoc(Loc, ExpansionLoc,
+ ExpansionLoc, Len);
Tok.setLocation(Loc);
// If this is a raw identifier or a literal token, set the pointer data.
@@ -528,10 +534,10 @@ CommentHandler::~CommentHandler() { }
CodeCompletionHandler::~CodeCompletionHandler() { }
void Preprocessor::createPreprocessingRecord(
- bool IncludeNestedMacroInstantiations) {
+ bool IncludeNestedMacroExpansions) {
if (Record)
return;
- Record = new PreprocessingRecord(IncludeNestedMacroInstantiations);
+ Record = new PreprocessingRecord(IncludeNestedMacroExpansions);
addPPCallbacks(Record);
}
diff --git a/lib/Lex/TokenLexer.cpp b/lib/Lex/TokenLexer.cpp
index 65aff0d1d037..8ff82f160033 100644
--- a/lib/Lex/TokenLexer.cpp
+++ b/lib/Lex/TokenLexer.cpp
@@ -23,7 +23,7 @@ using namespace clang;
/// Create a TokenLexer for the specified macro with the specified actual
/// arguments. Note that this ctor takes ownership of the ActualArgs pointer.
-void TokenLexer::Init(Token &Tok, SourceLocation ILEnd, MacroArgs *Actuals) {
+void TokenLexer::Init(Token &Tok, SourceLocation ELEnd, MacroArgs *Actuals) {
// If the client is reusing a TokenLexer, make sure to free any memory
// associated with it.
destroy();
@@ -32,14 +32,36 @@ void TokenLexer::Init(Token &Tok, SourceLocation ILEnd, MacroArgs *Actuals) {
ActualArgs = Actuals;
CurToken = 0;
- InstantiateLocStart = Tok.getLocation();
- InstantiateLocEnd = ILEnd;
+ ExpandLocStart = Tok.getLocation();
+ ExpandLocEnd = ELEnd;
AtStartOfLine = Tok.isAtStartOfLine();
HasLeadingSpace = Tok.hasLeadingSpace();
Tokens = &*Macro->tokens_begin();
OwnsTokens = false;
DisableMacroExpansion = false;
NumTokens = Macro->tokens_end()-Macro->tokens_begin();
+ MacroExpansionStart = SourceLocation();
+
+ SourceManager &SM = PP.getSourceManager();
+ MacroStartSLocOffset = SM.getNextOffset();
+
+ if (NumTokens > 0) {
+ assert(Tokens[0].getLocation().isValid());
+ assert((Tokens[0].getLocation().isFileID() || Tokens[0].is(tok::comment)) &&
+ "Macro defined in macro?");
+ assert(ExpandLocStart.isValid());
+
+ // Reserve a source location entry chunk for the length of the macro
+ // definition. Tokens that get lexed directly from the definition will
+ // have their locations pointing inside this chunk. This is to avoid
+ // creating separate source location entries for each token.
+ SourceLocation macroStart = SM.getInstantiationLoc(Tokens[0].getLocation());
+ MacroDefStartInfo = SM.getDecomposedLoc(macroStart);
+ MacroExpansionStart = SM.createInstantiationLoc(macroStart,
+ ExpandLocStart,
+ ExpandLocEnd,
+ Macro->getDefinitionLength(SM));
+ }
// If this is a function-like macro, expand the arguments and change
// Tokens to point to the expanded tokens.
@@ -69,9 +91,10 @@ void TokenLexer::Init(const Token *TokArray, unsigned NumToks,
DisableMacroExpansion = disableMacroExpansion;
NumTokens = NumToks;
CurToken = 0;
- InstantiateLocStart = InstantiateLocEnd = SourceLocation();
+ ExpandLocStart = ExpandLocEnd = SourceLocation();
AtStartOfLine = false;
HasLeadingSpace = false;
+ MacroExpansionStart = SourceLocation();
// Set HasLeadingSpace/AtStartOfLine so that the first token will be
// returned unmodified.
@@ -98,6 +121,8 @@ void TokenLexer::destroy() {
/// Expand the arguments of a function-like macro so that we can quickly
/// return preexpanded tokens from Tokens.
void TokenLexer::ExpandFunctionArguments() {
+ SourceManager &SM = PP.getSourceManager();
+
llvm::SmallVector<Token, 128> ResultToks;
// Loop through 'Tokens', expanding them into ResultToks. Keep
@@ -119,13 +144,19 @@ void TokenLexer::ExpandFunctionArguments() {
int ArgNo = Macro->getArgumentNum(Tokens[i+1].getIdentifierInfo());
assert(ArgNo != -1 && "Token following # is not an argument?");
+ SourceLocation hashInstLoc;
+ if(ExpandLocStart.isValid()) {
+ hashInstLoc = getMacroExpansionLocation(CurTok.getLocation());
+ assert(hashInstLoc.isValid() && "Expected '#' to come from definition");
+ }
+
Token Res;
if (CurTok.is(tok::hash)) // Stringify
- Res = ActualArgs->getStringifiedArgument(ArgNo, PP);
+ Res = ActualArgs->getStringifiedArgument(ArgNo, PP, hashInstLoc);
else {
// 'charify': don't bother caching these.
Res = MacroArgs::StringifyArgument(ActualArgs->getUnexpArgument(ArgNo),
- PP, true);
+ PP, true, hashInstLoc);
}
// The stringified/charified string leading space flag gets set to match
@@ -185,6 +216,27 @@ void TokenLexer::ExpandFunctionArguments() {
unsigned NumToks = MacroArgs::getArgLength(ResultArgToks);
ResultToks.append(ResultArgToks, ResultArgToks+NumToks);
+ // If the '##' came from expanding an argument, turn it into 'unknown'
+ // to avoid pasting.
+ for (unsigned i = FirstResult, e = ResultToks.size(); i != e; ++i) {
+ Token &Tok = ResultToks[i];
+ if (Tok.is(tok::hashhash))
+ Tok.setKind(tok::unknown);
+ }
+
+ if(ExpandLocStart.isValid()) {
+ SourceLocation curInst =
+ getMacroExpansionLocation(CurTok.getLocation());
+ assert(curInst.isValid() &&
+ "Expected arg identifier to come from definition");
+ for (unsigned i = FirstResult, e = ResultToks.size(); i != e; ++i) {
+ Token &Tok = ResultToks[i];
+ Tok.setLocation(SM.createMacroArgInstantiationLoc(Tok.getLocation(),
+ curInst,
+ Tok.getLength()));
+ }
+ }
+
// If any tokens were substituted from the argument, the whitespace
// before the first token should match the whitespace of the arg
// identifier.
@@ -220,6 +272,29 @@ void TokenLexer::ExpandFunctionArguments() {
ResultToks.append(ArgToks, ArgToks+NumToks);
+ // If the '##' came from expanding an argument, turn it into 'unknown'
+ // to avoid pasting.
+ for (unsigned i = ResultToks.size() - NumToks, e = ResultToks.size();
+ i != e; ++i) {
+ Token &Tok = ResultToks[i];
+ if (Tok.is(tok::hashhash))
+ Tok.setKind(tok::unknown);
+ }
+
+ if (ExpandLocStart.isValid()) {
+ SourceLocation curInst =
+ getMacroExpansionLocation(CurTok.getLocation());
+ assert(curInst.isValid() &&
+ "Expected arg identifier to come from definition");
+ for (unsigned i = ResultToks.size() - NumToks, e = ResultToks.size();
+ i != e; ++i) {
+ Token &Tok = ResultToks[i];
+ Tok.setLocation(SM.createMacroArgInstantiationLoc(Tok.getLocation(),
+ curInst,
+ Tok.getLength()));
+ }
+ }
+
// If this token (the macro argument) was supposed to get leading
// whitespace, transfer this information onto the first token of the
// expansion.
@@ -284,15 +359,11 @@ void TokenLexer::ExpandFunctionArguments() {
assert(!OwnsTokens && "This would leak if we already own the token list");
// This is deleted in the dtor.
NumTokens = ResultToks.size();
- llvm::BumpPtrAllocator &Alloc = PP.getPreprocessorAllocator();
- Token *Res =
- static_cast<Token *>(Alloc.Allocate(sizeof(Token)*ResultToks.size(),
- llvm::alignOf<Token>()));
- if (NumTokens)
- memcpy(Res, &ResultToks[0], NumTokens*sizeof(Token));
- Tokens = Res;
-
- // The preprocessor bump pointer owns these tokens, not us.
+ // The tokens will be added to Preprocessor's cache and will be removed
+ // when this TokenLexer finishes lexing them.
+ Tokens = PP.cacheMacroExpandedTokens(this, ResultToks);
+
+ // The preprocessor cache of macro expanded tokens owns these tokens,not us.
OwnsTokens = false;
}
}
@@ -317,6 +388,8 @@ void TokenLexer::Lex(Token &Tok) {
return PPCache.Lex(Tok);
}
+ SourceManager &SM = PP.getSourceManager();
+
// If this is the first token of the expanded result, we inherit spacing
// properties later.
bool isFirstToken = CurToken == 0;
@@ -327,7 +400,8 @@ void TokenLexer::Lex(Token &Tok) {
bool TokenIsFromPaste = false;
// If this token is followed by a token paste (##) operator, paste the tokens!
- if (!isAtEnd() && Tokens[CurToken].is(tok::hashhash)) {
+ // Note that ## is a normal token when not expanding a macro.
+ if (!isAtEnd() && Tokens[CurToken].is(tok::hashhash) && Macro) {
// When handling the microsoft /##/ extension, the final token is
// returned by PasteTokens, not the pasted token.
if (PasteTokens(Tok))
@@ -339,14 +413,25 @@ void TokenLexer::Lex(Token &Tok) {
// The token's current location indicate where the token was lexed from. We
// need this information to compute the spelling of the token, but any
// diagnostics for the expanded token should appear as if they came from
- // InstantiationLoc. Pull this information together into a new SourceLocation
+ // ExpansionLoc. Pull this information together into a new SourceLocation
// that captures all of this.
- if (InstantiateLocStart.isValid()) { // Don't do this for token streams.
- SourceManager &SM = PP.getSourceManager();
- Tok.setLocation(SM.createInstantiationLoc(Tok.getLocation(),
- InstantiateLocStart,
- InstantiateLocEnd,
- Tok.getLength()));
+ if (ExpandLocStart.isValid() && // Don't do this for token streams.
+ // Check that the token's location was not already set properly.
+ SM.isBeforeInSourceLocationOffset(Tok.getLocation(),
+ MacroStartSLocOffset)) {
+ SourceLocation instLoc;
+ if (Tok.is(tok::comment)) {
+ instLoc = SM.createInstantiationLoc(Tok.getLocation(),
+ ExpandLocStart,
+ ExpandLocEnd,
+ Tok.getLength());
+ } else {
+ instLoc = getMacroExpansionLocation(Tok.getLocation());
+ assert(instLoc.isValid() &&
+ "Location for token not coming from definition was not set!");
+ }
+
+ Tok.setLocation(instLoc);
}
// If this is the first token, set the lexical properties of the token to
@@ -384,9 +469,10 @@ void TokenLexer::Lex(Token &Tok) {
bool TokenLexer::PasteTokens(Token &Tok) {
llvm::SmallString<128> Buffer;
const char *ResultTokStrPtr = 0;
+ SourceLocation PasteOpLoc;
do {
// Consume the ## operator.
- SourceLocation PasteOpLoc = Tokens[CurToken].getLocation();
+ PasteOpLoc = Tokens[CurToken].getLocation();
++CurToken;
assert(!isAtEnd() && "No token on the RHS of a paste operator!");
@@ -484,12 +570,12 @@ bool TokenLexer::PasteTokens(Token &Tok) {
// Do not emit the error when preprocessing assembler code.
if (!PP.getLangOptions().AsmPreprocessor) {
- // Explicitly convert the token location to have proper instantiation
+ // Explicitly convert the token location to have proper expansion
// information so that the user knows where it came from.
SourceManager &SM = PP.getSourceManager();
SourceLocation Loc =
- SM.createInstantiationLoc(PasteOpLoc, InstantiateLocStart,
- InstantiateLocEnd, 2);
+ SM.createInstantiationLoc(PasteOpLoc, ExpandLocStart,
+ ExpandLocEnd, 2);
// If we're in microsoft extensions mode, downgrade this from a hard
// error to a warning that defaults to an error. This allows
// disabling it.
@@ -512,12 +598,30 @@ bool TokenLexer::PasteTokens(Token &Tok) {
// Transfer properties of the LHS over the the Result.
Result.setFlagValue(Token::StartOfLine , Tok.isAtStartOfLine());
Result.setFlagValue(Token::LeadingSpace, Tok.hasLeadingSpace());
-
+
// Finally, replace LHS with the result, consume the RHS, and iterate.
++CurToken;
Tok = Result;
} while (!isAtEnd() && Tokens[CurToken].is(tok::hashhash));
+ // The token's current location indicate where the token was lexed from. We
+ // need this information to compute the spelling of the token, but any
+ // diagnostics for the expanded token should appear as if the token was
+ // expanded from the (##) operator. Pull this information together into
+ // a new SourceLocation that captures all of this.
+ if (ExpandLocStart.isValid()) {
+ SourceManager &SM = PP.getSourceManager();
+ SourceLocation pasteLocInst =
+ getMacroExpansionLocation(PasteOpLoc);
+ assert(pasteLocInst.isValid() &&
+ "Expected '##' to come from definition");
+
+ Tok.setLocation(SM.createInstantiationLoc(Tok.getLocation(),
+ pasteLocInst,
+ pasteLocInst,
+ Tok.getLength()));
+ }
+
// Now that we got the result token, it will be subject to expansion. Since
// token pasting re-lexes the result token in raw mode, identifier information
// isn't looked up. As such, if the result is an identifier, look up id info.
@@ -548,7 +652,7 @@ bool TokenLexer::isParsingPreprocessorDirective() const {
/// 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 TokenLexer::HandleMicrosoftCommentPaste(Token &Tok) {
// We 'comment out' the rest of this macro by just ignoring the rest of the
@@ -561,3 +665,23 @@ void TokenLexer::HandleMicrosoftCommentPaste(Token &Tok) {
PP.HandleMicrosoftCommentPaste(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 TokenLexer::getMacroExpansionLocation(SourceLocation loc) const {
+ assert(ExpandLocStart.isValid() && MacroExpansionStart.isValid() &&
+ "Not appropriate for token streams");
+ assert(loc.isValid());
+
+ SourceManager &SM = PP.getSourceManager();
+ unsigned relativeOffset;
+ if (loc.isFileID() &&
+ SM.isInFileID(loc,
+ MacroDefStartInfo.first, MacroDefStartInfo.second,
+ Macro->getDefinitionLength(SM), &relativeOffset)) {
+ return MacroExpansionStart.getFileLocWithOffset(relativeOffset);
+ }
+
+ return SourceLocation();
+}
diff --git a/lib/Makefile b/lib/Makefile
index 924819c81807..74df7abcef24 100755
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -9,8 +9,8 @@
CLANG_LEVEL := ..
PARALLEL_DIRS = Headers Basic Lex Parse AST Sema CodeGen Analysis \
- StaticAnalyzer Rewrite Serialization Frontend FrontendTool \
- Index Driver
+ StaticAnalyzer Rewrite ARCMigrate Serialization Frontend \
+ FrontendTool Index Driver
include $(CLANG_LEVEL)/Makefile
diff --git a/lib/Parse/ParseAST.cpp b/lib/Parse/ParseAST.cpp
index 21917b23ffb6..56584c96180b 100644
--- a/lib/Parse/ParseAST.cpp
+++ b/lib/Parse/ParseAST.cpp
@@ -57,6 +57,10 @@ void clang::ParseAST(Sema &S, bool PrintStats) {
Stmt::CollectingStats(true);
}
+ // Also turn on collection of stats inside of the Sema object.
+ bool OldCollectStats = PrintStats;
+ std::swap(OldCollectStats, S.CollectStats);
+
ASTConsumer *Consumer = &S.getASTConsumer();
llvm::OwningPtr<Parser> ParseOP(new Parser(S.getPreprocessor(), S));
@@ -95,9 +99,10 @@ void clang::ParseAST(Sema &S, bool PrintStats) {
Consumer->HandleTopLevelDecl(DeclGroupRef(*I));
Consumer->HandleTranslationUnit(S.getASTContext());
-
+
+ std::swap(OldCollectStats, S.CollectStats);
if (PrintStats) {
- fprintf(stderr, "\nSTATISTICS:\n");
+ llvm::errs() << "\nSTATISTICS:\n";
P.getActions().PrintStats();
S.getASTContext().PrintStats();
Decl::PrintStats();
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index ad3fcfe0d369..0e17295858b9 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -31,10 +31,16 @@ using namespace clang;
///
/// Called type-id in C++.
TypeResult Parser::ParseTypeName(SourceRange *Range,
- Declarator::TheContext Context) {
+ Declarator::TheContext Context,
+ ObjCDeclSpec *objcQuals,
+ AccessSpecifier AS,
+ Decl **OwnedType) {
// Parse the common declaration-specifiers piece.
DeclSpec DS(AttrFactory);
- ParseSpecifierQualifierList(DS);
+ DS.setObjCQualifiers(objcQuals);
+ ParseSpecifierQualifierList(DS, AS);
+ if (OwnedType)
+ *OwnedType = DS.isTypeSpecOwned() ? DS.getRepAsDecl() : 0;
// Parse the abstract-declarator, if present.
Declarator DeclaratorInfo(DS, Context);
@@ -672,6 +678,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts,
ParenBraceBracketBalancer BalancerRAIIObj(*this);
Decl *SingleDecl = 0;
+ Decl *OwnedType = 0;
switch (Tok.getKind()) {
case tok::kw_template:
case tok::kw_export:
@@ -694,7 +701,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts,
break;
case tok::kw_using:
SingleDecl = ParseUsingDirectiveOrDeclaration(Context, ParsedTemplateInfo(),
- DeclEnd, attrs);
+ DeclEnd, attrs, &OwnedType);
break;
case tok::kw_static_assert:
case tok::kw__Static_assert:
@@ -706,8 +713,9 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts,
}
// This routine returns a DeclGroup, if the thing we parsed only contains a
- // single decl, convert it now.
- return Actions.ConvertDeclToDeclGroup(SingleDecl);
+ // single decl, convert it now. Alias declarations can also declare a type;
+ // include that too if it is present.
+ return Actions.ConvertDeclToDeclGroup(SingleDecl, OwnedType);
}
/// simple-declaration: [C99 6.7: declaration] [C++ 7p1: dcl.dcl]
@@ -1079,10 +1087,10 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
/// type-qualifier specifier-qualifier-list[opt]
/// [GNU] attributes specifier-qualifier-list[opt]
///
-void Parser::ParseSpecifierQualifierList(DeclSpec &DS) {
+void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS) {
/// specifier-qualifier-list is a subset of declaration-specifiers. Just
/// parse declaration-specifiers and complain about extra stuff.
- ParseDeclarationSpecifiers(DS);
+ ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS);
// Validate declspec for type-name.
unsigned Specs = DS.getParsedSpecifiers();
@@ -1394,8 +1402,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// Thus, if the template-name is actually the constructor
// name, then the code is ill-formed; this interpretation is
// reinforced by the NAD status of core issue 635.
- TemplateIdAnnotation *TemplateId
- = static_cast<TemplateIdAnnotation *>(Next.getAnnotationValue());
+ TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Next);
if ((DSContext == DSC_top_level ||
(DSContext == DSC_class && DS.isFriendSpecified())) &&
TemplateId->Name &&
@@ -1597,8 +1604,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// type-name
case tok::annot_template_id: {
- TemplateIdAnnotation *TemplateId
- = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+ TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
if (TemplateId->Kind != TNK_Type_template) {
// This template-id does not refer to a type name, so we're
// done with the type-specifiers.
@@ -2444,13 +2450,29 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
Actions.CodeCompleteTag(getCurScope(), DeclSpec::TST_enum);
ConsumeCodeCompletionToken();
}
+
+ bool IsScopedEnum = false;
+ bool IsScopedUsingClassTag = false;
+
+ if (getLang().CPlusPlus0x &&
+ (Tok.is(tok::kw_class) || Tok.is(tok::kw_struct))) {
+ IsScopedEnum = true;
+ IsScopedUsingClassTag = Tok.is(tok::kw_class);
+ ConsumeToken();
+ }
// If attributes exist after tag, parse them.
ParsedAttributes attrs(AttrFactory);
MaybeParseGNUAttributes(attrs);
+ bool AllowFixedUnderlyingType = getLang().CPlusPlus0x || getLang().Microsoft;
+
CXXScopeSpec &SS = DS.getTypeSpecScope();
if (getLang().CPlusPlus) {
+ // "enum foo : bar;" is not a potential typo for "enum foo::bar;"
+ // if a fixed underlying type is allowed.
+ ColonProtectionRAIIObject X(*this, AllowFixedUnderlyingType);
+
if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false))
return;
@@ -2465,17 +2487,6 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
}
}
- bool AllowFixedUnderlyingType = getLang().CPlusPlus0x || getLang().Microsoft;
- bool IsScopedEnum = false;
- bool IsScopedUsingClassTag = false;
-
- if (getLang().CPlusPlus0x &&
- (Tok.is(tok::kw_class) || Tok.is(tok::kw_struct))) {
- IsScopedEnum = true;
- IsScopedUsingClassTag = Tok.is(tok::kw_class);
- ConsumeToken();
- }
-
// Must have either 'enum name' or 'enum {...}'.
if (Tok.isNot(tok::identifier) && Tok.isNot(tok::l_brace) &&
(AllowFixedUnderlyingType && Tok.isNot(tok::colon))) {
@@ -3016,6 +3027,10 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
case tok::kw___attribute:
return true;
+ // C++0x decltype.
+ case tok::kw_decltype:
+ return true;
+
// GNU ObjC bizarre protocol extension: <proto1,proto2> with implicit 'id'.
case tok::less:
return getLang().ObjC1;
@@ -3639,33 +3654,15 @@ void Parser::ParseParenDeclarator(Declarator &D) {
/// declarator D up to a paren, which indicates that we are parsing function
/// arguments.
///
-/// If AttrList is non-null, then the caller parsed those arguments immediately
+/// If attrs is non-null, then the caller parsed those arguments immediately
/// after the open paren - they should be considered to be the first argument of
/// a parameter. If RequiresArg is true, then the first argument of the
/// function is required to be present and required to not be an identifier
/// list.
///
-/// This method also handles this portion of the grammar:
-/// parameter-type-list: [C99 6.7.5]
-/// parameter-list
-/// parameter-list ',' '...'
-/// [C++] parameter-list '...'
-///
-/// parameter-list: [C99 6.7.5]
-/// parameter-declaration
-/// parameter-list ',' parameter-declaration
-///
-/// parameter-declaration: [C99 6.7.5]
-/// declaration-specifiers declarator
-/// [C++] declaration-specifiers declarator '=' assignment-expression
-/// [GNU] declaration-specifiers declarator attributes
-/// declaration-specifiers abstract-declarator[opt]
-/// [C++] declaration-specifiers abstract-declarator[opt]
-/// '=' assignment-expression
-/// [GNU] declaration-specifiers abstract-declarator[opt] attributes
-///
-/// For C++, after the parameter-list, it also parses "cv-qualifier-seq[opt]",
-/// C++0x "ref-qualifier[opt]" and "exception-specification[opt]".
+/// For C++, after the parameter-list, it also parses cv-qualifier-seq[opt],
+/// (C++0x) ref-qualifier[opt], exception-specification[opt], and
+/// (C++0x) trailing-return-type[opt].
///
/// [C++0x] exception-specification:
/// dynamic-exception-specification
@@ -3677,36 +3674,62 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
// lparen is already consumed!
assert(D.isPastIdentifier() && "Should not call before identifier!");
+ // This should be true when the function has typed arguments.
+ // Otherwise, it is treated as a K&R-style function.
+ bool HasProto = false;
+ // Build up an array of information about the parsed arguments.
+ llvm::SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
+ // Remember where we see an ellipsis, if any.
+ SourceLocation EllipsisLoc;
+
+ DeclSpec DS(AttrFactory);
+ bool RefQualifierIsLValueRef = true;
+ SourceLocation RefQualifierLoc;
+ ExceptionSpecificationType ESpecType = EST_None;
+ SourceRange ESpecRange;
+ llvm::SmallVector<ParsedType, 2> DynamicExceptions;
+ llvm::SmallVector<SourceRange, 2> DynamicExceptionRanges;
+ ExprResult NoexceptExpr;
ParsedType TrailingReturnType;
+
+ SourceLocation EndLoc;
- // This parameter list may be empty.
- if (Tok.is(tok::r_paren)) {
+ if (isFunctionDeclaratorIdentifierList()) {
if (RequiresArg)
Diag(Tok, diag::err_argument_required_after_attribute);
- SourceLocation EndLoc = ConsumeParen(); // Eat the closing ')'.
+ ParseFunctionDeclaratorIdentifierList(D, ParamInfo);
+
+ EndLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ } else {
+ // Enter function-declaration scope, limiting any declarators to the
+ // function prototype scope, including parameter declarators.
+ ParseScope PrototypeScope(this,
+ Scope::FunctionPrototypeScope|Scope::DeclScope);
+
+ if (Tok.isNot(tok::r_paren))
+ ParseParameterDeclarationClause(D, attrs, ParamInfo, EllipsisLoc);
+ else if (RequiresArg)
+ Diag(Tok, diag::err_argument_required_after_attribute);
+
+ HasProto = ParamInfo.size() || getLang().CPlusPlus;
+
+ // If we have the closing ')', eat it.
+ EndLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
- // cv-qualifier-seq[opt].
- DeclSpec DS(AttrFactory);
- SourceLocation RefQualifierLoc;
- bool RefQualifierIsLValueRef = true;
- ExceptionSpecificationType ESpecType = EST_None;
- SourceRange ESpecRange;
- llvm::SmallVector<ParsedType, 2> DynamicExceptions;
- llvm::SmallVector<SourceRange, 2> DynamicExceptionRanges;
- ExprResult NoexceptExpr;
if (getLang().CPlusPlus) {
MaybeParseCXX0XAttributes(attrs);
+ // Parse cv-qualifier-seq[opt].
ParseTypeQualifierListOpt(DS, false /*no attributes*/);
- if (!DS.getSourceRange().getEnd().isInvalid())
- EndLoc = DS.getSourceRange().getEnd();
+ if (!DS.getSourceRange().getEnd().isInvalid())
+ EndLoc = DS.getSourceRange().getEnd();
- // Parse ref-qualifier[opt]
+ // Parse ref-qualifier[opt].
if (Tok.is(tok::amp) || Tok.is(tok::ampamp)) {
if (!getLang().CPlusPlus0x)
Diag(Tok, diag::ext_ref_qualifier);
-
+
RefQualifierIsLValueRef = Tok.is(tok::amp);
RefQualifierLoc = ConsumeToken();
EndLoc = RefQualifierLoc;
@@ -3720,87 +3743,158 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
if (ESpecType != EST_None)
EndLoc = ESpecRange.getEnd();
- // Parse trailing-return-type.
+ // Parse trailing-return-type[opt].
if (getLang().CPlusPlus0x && Tok.is(tok::arrow)) {
TrailingReturnType = ParseTrailingReturnType().get();
}
}
- // Remember that we parsed a function type, and remember the attributes.
- // int() -> no prototype, no '...'.
- D.AddTypeInfo(DeclaratorChunk::getFunction(/*prototype*/getLang().CPlusPlus,
- /*variadic*/ false,
- SourceLocation(),
- /*arglist*/ 0, 0,
- DS.getTypeQualifiers(),
- RefQualifierIsLValueRef,
- RefQualifierLoc,
- ESpecType, ESpecRange.getBegin(),
- DynamicExceptions.data(),
- DynamicExceptionRanges.data(),
- DynamicExceptions.size(),
- NoexceptExpr.isUsable() ?
- NoexceptExpr.get() : 0,
- LParenLoc, EndLoc, D,
- TrailingReturnType),
- attrs, EndLoc);
- return;
+ // Leave prototype scope.
+ PrototypeScope.Exit();
}
- // Alternatively, this parameter list may be an identifier list form for a
- // K&R-style function: void foo(a,b,c)
- if (!getLang().CPlusPlus && Tok.is(tok::identifier)
- && !TryAltiVecVectorToken()) {
- if (TryAnnotateTypeOrScopeToken() || !Tok.is(tok::annot_typename)) {
- // K&R identifier lists can't have typedefs as identifiers, per
- // C99 6.7.5.3p11.
- if (RequiresArg)
- Diag(Tok, diag::err_argument_required_after_attribute);
-
- // Identifier list. Note that '(' identifier-list ')' is only allowed for
- // normal declarators, not for abstract-declarators. Get the first
- // identifier.
- Token FirstTok = Tok;
- ConsumeToken(); // eat the first identifier.
-
- // Identifier lists follow a really simple grammar: the identifiers can
- // be followed *only* by a ", moreidentifiers" or ")". However, K&R
- // identifier lists are really rare in the brave new modern world, and it
- // is very common for someone to typo a type in a non-k&r style list. If
- // we are presented with something like: "void foo(intptr x, float y)",
- // we don't want to start parsing the function declarator as though it is
- // a K&R style declarator just because intptr is an invalid type.
- //
- // To handle this, we check to see if the token after the first identifier
- // is a "," or ")". Only if so, do we parse it as an identifier list.
- if (Tok.is(tok::comma) || Tok.is(tok::r_paren))
- return ParseFunctionDeclaratorIdentifierList(LParenLoc,
- FirstTok.getIdentifierInfo(),
- FirstTok.getLocation(), D);
-
- // If we get here, the code is invalid. Push the first identifier back
- // into the token stream and parse the first argument as an (invalid)
- // normal argument declarator.
- PP.EnterToken(Tok);
- Tok = FirstTok;
+ // Remember that we parsed a function type, and remember the attributes.
+ D.AddTypeInfo(DeclaratorChunk::getFunction(HasProto,
+ /*isVariadic=*/EllipsisLoc.isValid(),
+ EllipsisLoc,
+ ParamInfo.data(), ParamInfo.size(),
+ DS.getTypeQualifiers(),
+ RefQualifierIsLValueRef,
+ RefQualifierLoc,
+ /*MutableLoc=*/SourceLocation(),
+ ESpecType, ESpecRange.getBegin(),
+ DynamicExceptions.data(),
+ DynamicExceptionRanges.data(),
+ DynamicExceptions.size(),
+ NoexceptExpr.isUsable() ?
+ NoexceptExpr.get() : 0,
+ LParenLoc, EndLoc, D,
+ TrailingReturnType),
+ attrs, EndLoc);
+}
+
+/// isFunctionDeclaratorIdentifierList - This parameter list may have an
+/// identifier list form for a K&R-style function: void foo(a,b,c)
+///
+/// Note that identifier-lists are only allowed for normal declarators, not for
+/// abstract-declarators.
+bool Parser::isFunctionDeclaratorIdentifierList() {
+ return !getLang().CPlusPlus
+ && Tok.is(tok::identifier)
+ && !TryAltiVecVectorToken()
+ // K&R identifier lists can't have typedefs as identifiers, per C99
+ // 6.7.5.3p11.
+ && (TryAnnotateTypeOrScopeToken() || !Tok.is(tok::annot_typename))
+ // Identifier lists follow a really simple grammar: the identifiers can
+ // be followed *only* by a ", identifier" or ")". However, K&R
+ // identifier lists are really rare in the brave new modern world, and
+ // it is very common for someone to typo a type in a non-K&R style
+ // list. If we are presented with something like: "void foo(intptr x,
+ // float y)", we don't want to start parsing the function declarator as
+ // though it is a K&R style declarator just because intptr is an
+ // invalid type.
+ //
+ // To handle this, we check to see if the token after the first
+ // identifier is a "," or ")". Only then do we parse it as an
+ // identifier list.
+ && (NextToken().is(tok::comma) || NextToken().is(tok::r_paren));
+}
+
+/// ParseFunctionDeclaratorIdentifierList - While parsing a function declarator
+/// we found a K&R-style identifier list instead of a typed parameter list.
+///
+/// After returning, ParamInfo will hold the parsed parameters.
+///
+/// identifier-list: [C99 6.7.5]
+/// identifier
+/// identifier-list ',' identifier
+///
+void Parser::ParseFunctionDeclaratorIdentifierList(
+ Declarator &D,
+ llvm::SmallVector<DeclaratorChunk::ParamInfo, 16> &ParamInfo) {
+ // If there was no identifier specified for the declarator, either we are in
+ // an abstract-declarator, or we are in a parameter declarator which was found
+ // to be abstract. In abstract-declarators, identifier lists are not valid:
+ // diagnose this.
+ if (!D.getIdentifier())
+ Diag(Tok, diag::ext_ident_list_in_param);
+
+ // Maintain an efficient lookup of params we have seen so far.
+ llvm::SmallSet<const IdentifierInfo*, 16> ParamsSoFar;
+
+ while (1) {
+ // If this isn't an identifier, report the error and skip until ')'.
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident);
+ SkipUntil(tok::r_paren, /*StopAtSemi=*/true, /*DontConsume=*/true);
+ // Forget we parsed anything.
+ ParamInfo.clear();
+ return;
}
- }
- // Finally, a normal, non-empty parameter type list.
+ IdentifierInfo *ParmII = Tok.getIdentifierInfo();
- // Build up an array of information about the parsed arguments.
- llvm::SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
+ // Reject 'typedef int y; int test(x, y)', but continue parsing.
+ if (Actions.getTypeName(*ParmII, Tok.getLocation(), getCurScope()))
+ Diag(Tok, diag::err_unexpected_typedef_ident) << ParmII;
+
+ // Verify that the argument identifier has not already been mentioned.
+ if (!ParamsSoFar.insert(ParmII)) {
+ Diag(Tok, diag::err_param_redefinition) << ParmII;
+ } else {
+ // Remember this identifier in ParamInfo.
+ ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII,
+ Tok.getLocation(),
+ 0));
+ }
+
+ // Eat the identifier.
+ ConsumeToken();
- // Enter function-declaration scope, limiting any declarators to the
- // function prototype scope, including parameter declarators.
- ParseScope PrototypeScope(this,
- Scope::FunctionPrototypeScope|Scope::DeclScope);
+ // The list continues if we see a comma.
+ if (Tok.isNot(tok::comma))
+ break;
+ ConsumeToken();
+ }
+}
+
+/// ParseParameterDeclarationClause - Parse a (possibly empty) parameter-list
+/// after the opening parenthesis. This function will not parse a K&R-style
+/// identifier list.
+///
+/// D is the declarator being parsed. If attrs is non-null, then the caller
+/// parsed those arguments immediately after the open paren - they should be
+/// considered to be the first argument of a parameter.
+///
+/// After returning, ParamInfo will hold the parsed parameters. EllipsisLoc will
+/// be the location of the ellipsis, if any was parsed.
+///
+/// parameter-type-list: [C99 6.7.5]
+/// parameter-list
+/// parameter-list ',' '...'
+/// [C++] parameter-list '...'
+///
+/// parameter-list: [C99 6.7.5]
+/// parameter-declaration
+/// parameter-list ',' parameter-declaration
+///
+/// parameter-declaration: [C99 6.7.5]
+/// declaration-specifiers declarator
+/// [C++] declaration-specifiers declarator '=' assignment-expression
+/// [GNU] declaration-specifiers declarator attributes
+/// declaration-specifiers abstract-declarator[opt]
+/// [C++] declaration-specifiers abstract-declarator[opt]
+/// '=' assignment-expression
+/// [GNU] declaration-specifiers abstract-declarator[opt] attributes
+///
+void Parser::ParseParameterDeclarationClause(
+ Declarator &D,
+ ParsedAttributes &attrs,
+ llvm::SmallVector<DeclaratorChunk::ParamInfo, 16> &ParamInfo,
+ SourceLocation &EllipsisLoc) {
- bool IsVariadic = false;
- SourceLocation EllipsisLoc;
while (1) {
if (Tok.is(tok::ellipsis)) {
- IsVariadic = true;
EllipsisLoc = ConsumeToken(); // Consume the ellipsis.
break;
}
@@ -3817,6 +3911,11 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
// If the caller parsed attributes for the first argument, add them now.
// Take them so that we only apply the attributes to the first parameter.
+ // FIXME: If we saw an ellipsis first, this code is not reached. Are the
+ // attributes lost? Should they even be allowed?
+ // FIXME: If we can leave the attributes in the token stream somehow, we can
+ // get rid of a parameter (attrs) and this statement. It might be too much
+ // hassle.
DS.takeAttributesFrom(attrs);
ParseDeclarationSpecifiers(DS);
@@ -3912,7 +4011,6 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
// If the next token is a comma, consume it and keep reading arguments.
if (Tok.isNot(tok::comma)) {
if (Tok.is(tok::ellipsis)) {
- IsVariadic = true;
EllipsisLoc = ConsumeToken(); // Consume the ellipsis.
if (!getLang().CPlusPlus) {
@@ -3930,150 +4028,6 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
ConsumeToken();
}
- // If we have the closing ')', eat it.
- SourceLocation EndLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
-
- DeclSpec DS(AttrFactory);
- SourceLocation RefQualifierLoc;
- bool RefQualifierIsLValueRef = true;
- ExceptionSpecificationType ESpecType = EST_None;
- SourceRange ESpecRange;
- llvm::SmallVector<ParsedType, 2> DynamicExceptions;
- llvm::SmallVector<SourceRange, 2> DynamicExceptionRanges;
- ExprResult NoexceptExpr;
-
- if (getLang().CPlusPlus) {
- MaybeParseCXX0XAttributes(attrs);
-
- // Parse cv-qualifier-seq[opt].
- ParseTypeQualifierListOpt(DS, false /*no attributes*/);
- if (!DS.getSourceRange().getEnd().isInvalid())
- EndLoc = DS.getSourceRange().getEnd();
-
- // Parse ref-qualifier[opt]
- if (Tok.is(tok::amp) || Tok.is(tok::ampamp)) {
- if (!getLang().CPlusPlus0x)
- Diag(Tok, diag::ext_ref_qualifier);
-
- RefQualifierIsLValueRef = Tok.is(tok::amp);
- RefQualifierLoc = ConsumeToken();
- EndLoc = RefQualifierLoc;
- }
-
- // FIXME: We should leave the prototype scope before parsing the exception
- // specification, and then reenter it when parsing the trailing return type.
- // FIXMEFIXME: Why? That wouldn't be right for the noexcept clause.
-
- // Parse exception-specification[opt].
- ESpecType = MaybeParseExceptionSpecification(ESpecRange,
- DynamicExceptions,
- DynamicExceptionRanges,
- NoexceptExpr);
- if (ESpecType != EST_None)
- EndLoc = ESpecRange.getEnd();
-
- // Parse trailing-return-type.
- if (getLang().CPlusPlus0x && Tok.is(tok::arrow)) {
- TrailingReturnType = ParseTrailingReturnType().get();
- }
- }
-
- // Leave prototype scope.
- PrototypeScope.Exit();
-
- // Remember that we parsed a function type, and remember the attributes.
- D.AddTypeInfo(DeclaratorChunk::getFunction(/*proto*/true, IsVariadic,
- EllipsisLoc,
- ParamInfo.data(), ParamInfo.size(),
- DS.getTypeQualifiers(),
- RefQualifierIsLValueRef,
- RefQualifierLoc,
- ESpecType, ESpecRange.getBegin(),
- DynamicExceptions.data(),
- DynamicExceptionRanges.data(),
- DynamicExceptions.size(),
- NoexceptExpr.isUsable() ?
- NoexceptExpr.get() : 0,
- LParenLoc, EndLoc, D,
- TrailingReturnType),
- attrs, EndLoc);
-}
-
-/// ParseFunctionDeclaratorIdentifierList - While parsing a function declarator
-/// we found a K&R-style identifier list instead of a type argument list. The
-/// first identifier has already been consumed, and the current token is the
-/// token right after it.
-///
-/// identifier-list: [C99 6.7.5]
-/// identifier
-/// identifier-list ',' identifier
-///
-void Parser::ParseFunctionDeclaratorIdentifierList(SourceLocation LParenLoc,
- IdentifierInfo *FirstIdent,
- SourceLocation FirstIdentLoc,
- Declarator &D) {
- // Build up an array of information about the parsed arguments.
- llvm::SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
- llvm::SmallSet<const IdentifierInfo*, 16> ParamsSoFar;
-
- // If there was no identifier specified for the declarator, either we are in
- // an abstract-declarator, or we are in a parameter declarator which was found
- // to be abstract. In abstract-declarators, identifier lists are not valid:
- // diagnose this.
- if (!D.getIdentifier())
- Diag(FirstIdentLoc, diag::ext_ident_list_in_param);
-
- // The first identifier was already read, and is known to be the first
- // identifier in the list. Remember this identifier in ParamInfo.
- ParamsSoFar.insert(FirstIdent);
- ParamInfo.push_back(DeclaratorChunk::ParamInfo(FirstIdent, FirstIdentLoc, 0));
-
- while (Tok.is(tok::comma)) {
- // Eat the comma.
- ConsumeToken();
-
- // If this isn't an identifier, report the error and skip until ')'.
- if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected_ident);
- SkipUntil(tok::r_paren);
- return;
- }
-
- IdentifierInfo *ParmII = Tok.getIdentifierInfo();
-
- // Reject 'typedef int y; int test(x, y)', but continue parsing.
- if (Actions.getTypeName(*ParmII, Tok.getLocation(), getCurScope()))
- Diag(Tok, diag::err_unexpected_typedef_ident) << ParmII;
-
- // Verify that the argument identifier has not already been mentioned.
- if (!ParamsSoFar.insert(ParmII)) {
- Diag(Tok, diag::err_param_redefinition) << ParmII;
- } else {
- // Remember this identifier in ParamInfo.
- ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII,
- Tok.getLocation(),
- 0));
- }
-
- // Eat the identifier.
- ConsumeToken();
- }
-
- // If we have the closing ')', eat it and we're done.
- SourceLocation RLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
-
- // Remember that we parsed a function type, and remember the attributes. This
- // function type is always a K&R style function type, which is not varargs and
- // has no prototype.
- ParsedAttributes attrs(AttrFactory);
- D.AddTypeInfo(DeclaratorChunk::getFunction(/*proto*/false, /*varargs*/false,
- SourceLocation(),
- &ParamInfo[0], ParamInfo.size(),
- /*TypeQuals*/0,
- true, SourceLocation(),
- EST_None, SourceLocation(), 0, 0,
- 0, 0, LParenLoc, RLoc, D),
- attrs, RLoc);
}
/// [C90] direct-declarator '[' constant-expression[opt] ']'
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 51aa01091e73..172049c34053 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -314,7 +314,8 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, unsigned Context) {
Decl *Parser::ParseUsingDirectiveOrDeclaration(unsigned Context,
const ParsedTemplateInfo &TemplateInfo,
SourceLocation &DeclEnd,
- ParsedAttributesWithRange &attrs) {
+ ParsedAttributesWithRange &attrs,
+ Decl **OwnedType) {
assert(Tok.is(tok::kw_using) && "Not using token");
// Eat 'using'.
@@ -342,7 +343,8 @@ Decl *Parser::ParseUsingDirectiveOrDeclaration(unsigned Context,
// Using declarations can't have attributes.
ProhibitAttributes(attrs);
- return ParseUsingDeclaration(Context, TemplateInfo, UsingLoc, DeclEnd);
+ return ParseUsingDeclaration(Context, TemplateInfo, UsingLoc, DeclEnd,
+ AS_none, OwnedType);
}
/// ParseUsingDirective - Parse C++ using-directive, assumes
@@ -422,7 +424,8 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
const ParsedTemplateInfo &TemplateInfo,
SourceLocation UsingLoc,
SourceLocation &DeclEnd,
- AccessSpecifier AS) {
+ AccessSpecifier AS,
+ Decl **OwnedType) {
CXXScopeSpec SS;
SourceLocation TypenameLoc;
bool IsTypeName;
@@ -511,7 +514,7 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
TypeAlias = ParseTypeName(0, TemplateInfo.Kind ?
Declarator::AliasTemplateContext :
- Declarator::AliasDeclContext);
+ Declarator::AliasDeclContext, 0, AS, OwnedType);
} else
// Parse (optional) attributes (most likely GNU strong-using extension).
MaybeParseGNUAttributes(attrs);
@@ -701,8 +704,7 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation,
CXXScopeSpec &SS) {
// Check whether we have a template-id that names a type.
if (Tok.is(tok::annot_template_id)) {
- TemplateIdAnnotation *TemplateId
- = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+ TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
if (TemplateId->Kind == TNK_Type_template ||
TemplateId->Kind == TNK_Dependent_template_name) {
AnnotateTemplateIdTokenAsType();
@@ -976,7 +978,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
}
}
} else if (Tok.is(tok::annot_template_id)) {
- TemplateId = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+ TemplateId = takeTemplateIdAnnotation(Tok);
NameLoc = ConsumeToken();
if (TemplateId->Kind != TNK_Type_template &&
@@ -993,7 +995,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
DS.SetTypeSpecError();
SkipUntil(tok::semi, false, true);
- TemplateId->Destroy();
if (SuppressingAccessChecks)
Actions.ActOnStopSuppressingAccessChecks();
@@ -1051,9 +1052,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
}
SkipUntil(tok::comma, true);
-
- if (TemplateId)
- TemplateId->Destroy();
return;
}
@@ -1149,7 +1147,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
TemplateParams? &(*TemplateParams)[0] : 0,
TemplateParams? TemplateParams->size() : 0));
}
- TemplateId->Destroy();
} else if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation &&
TUK == Sema::TUK_Declaration) {
// Explicit instantiation of a member of a class template
@@ -1294,6 +1291,11 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
break;
}
+ // C++ [temp]p3 In a template-declaration which defines a class, no
+ // declarator is permitted.
+ if (TemplateInfo.Kind)
+ ExpectedSemi = true;
+
if (ExpectedSemi) {
ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl,
TagType == DeclSpec::TST_class ? "class"
@@ -1828,14 +1830,16 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
Diag(Tok, diag::err_bitfield_member_init);
SkipUntil(tok::comma, true, true);
} else {
- HasDeferredInitializer = !DeclaratorInfo.isFunctionDeclarator() &&
+ HasDeferredInitializer = !DeclaratorInfo.isDeclarationOfFunction() &&
+ DeclaratorInfo.getDeclSpec().getStorageClassSpec()
+ != DeclSpec::SCS_static &&
DeclaratorInfo.getDeclSpec().getStorageClassSpec()
- != DeclSpec::SCS_static;
+ != DeclSpec::SCS_typedef;
if (!HasDeferredInitializer) {
SourceLocation EqualLoc;
Init = ParseCXXMemberInitializer(
- DeclaratorInfo.isFunctionDeclarator(), EqualLoc);
+ DeclaratorInfo.isDeclarationOfFunction(), EqualLoc);
if (Init.isInvalid())
SkipUntil(tok::comma, true, true);
}
@@ -2246,8 +2250,7 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false);
ParsedType TemplateTypeTy;
if (Tok.is(tok::annot_template_id)) {
- TemplateIdAnnotation *TemplateId
- = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+ TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
if (TemplateId->Kind == TNK_Type_template ||
TemplateId->Kind == TNK_Dependent_template_name) {
AnnotateTemplateIdTokenAsType();
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index 4e94ed9323b8..fc64ae022654 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -220,7 +220,7 @@ ExprResult Parser::ParseAssignmentExpression() {
if (Tok.is(tok::kw_throw))
return ParseThrowExpression();
- ExprResult LHS = ParseCastExpression(false, false, ParsedType());
+ ExprResult LHS = ParseCastExpression(/*isUnaryExpression=*/false);
return ParseRHSOfBinaryExpression(move(LHS), prec::Assignment);
}
@@ -304,13 +304,14 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
ColonLoc = ConsumeToken();
} else {
// Otherwise, we're missing a ':'. Assume that this was a typo that the
- // user forgot. If we're not in a macro instantion, we can suggest a
+ // user forgot. If we're not in a macro instantiation, we can suggest a
// fixit hint. If there were two spaces before the current token,
// suggest inserting the colon in between them, otherwise insert ": ".
SourceLocation FILoc = Tok.getLocation();
const char *FIText = ": ";
- if (FILoc.isFileID()) {
- const SourceManager &SM = PP.getSourceManager();
+ const SourceManager &SM = PP.getSourceManager();
+ if (FILoc.isFileID() || PP.isAtStartOfMacroExpansion(FILoc)) {
+ FILoc = SM.getInstantiationLoc(FILoc);
bool IsInvalid = false;
const char *SourcePtr =
SM.getCharacterData(FILoc.getFileLocWithOffset(-1), &IsInvalid);
@@ -414,12 +415,12 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
///
ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
bool isAddressOfOperand,
- ParsedType TypeOfCast) {
+ bool isTypeCast) {
bool NotCastExpr;
ExprResult Res = ParseCastExpression(isUnaryExpression,
isAddressOfOperand,
NotCastExpr,
- TypeOfCast);
+ isTypeCast);
if (NotCastExpr)
Diag(Tok, diag::err_expected_expression);
return move(Res);
@@ -588,7 +589,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
bool isAddressOfOperand,
bool &NotCastExpr,
- ParsedType TypeOfCast) {
+ bool isTypeCast) {
ExprResult Res;
tok::TokenKind SavedKind = Tok.getKind();
NotCastExpr = false;
@@ -619,7 +620,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
ColonProtectionRAIIObject X(*this, false);
Res = ParseParenExpression(ParenExprType, false/*stopIfCastExr*/,
- TypeOfCast, CastTy, RParenLoc);
+ isTypeCast, CastTy, RParenLoc);
}
switch (ParenExprType) {
@@ -791,7 +792,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
return ParseBuiltinPrimaryExpression();
case tok::kw___null:
return Actions.ActOnGNUNullExpr(ConsumeToken());
- break;
+
case tok::plusplus: // unary-expression: '++' unary-expression [C99]
case tok::minusminus: { // unary-expression: '--' unary-expression [C99]
// C++ [expr.unary] has:
@@ -951,12 +952,11 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
return ExprError();
if (!Tok.is(tok::annot_cxxscope))
return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
- NotCastExpr, TypeOfCast);
+ NotCastExpr, isTypeCast);
Token Next = NextToken();
if (Next.is(tok::annot_template_id)) {
- TemplateIdAnnotation *TemplateId
- = static_cast<TemplateIdAnnotation *>(Next.getAnnotationValue());
+ TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Next);
if (TemplateId->Kind == TNK_Type_template) {
// We have a qualified template-id that we know refers to a
// type, translate it into a type and continue parsing as a
@@ -965,7 +965,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false);
AnnotateTemplateIdTokenAsType();
return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
- NotCastExpr, TypeOfCast);
+ NotCastExpr, isTypeCast);
}
}
@@ -975,15 +975,14 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
}
case tok::annot_template_id: { // [C++] template-id
- TemplateIdAnnotation *TemplateId
- = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+ TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
if (TemplateId->Kind == TNK_Type_template) {
// We have a template-id that we know refers to a type,
// translate it into a type and continue parsing as a cast
// expression.
AnnotateTemplateIdTokenAsType();
return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
- NotCastExpr, TypeOfCast);
+ NotCastExpr, isTypeCast);
}
// Fall through to treat the template-id as an id-expression.
@@ -1101,17 +1100,20 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
return ParseObjCAtExpression(AtLoc);
}
case tok::caret:
- return ParsePostfixExpressionSuffix(ParseBlockLiteralExpression());
- case tok::code_completion:
+ Res = ParseBlockLiteralExpression();
+ break;
+ case tok::code_completion: {
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression);
ConsumeCodeCompletionToken();
return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
- NotCastExpr, TypeOfCast);
+ NotCastExpr, isTypeCast);
+ }
case tok::l_square:
- // These can be followed by postfix-expr pieces.
- if (getLang().ObjC1)
- return ParsePostfixExpressionSuffix(ParseObjCMessageExpression());
- // FALL THROUGH.
+ if (getLang().ObjC1) {
+ Res = ParseObjCMessageExpression();
+ break;
+ }
+ // FALL THROUGH.
default:
NotCastExpr = true;
return ExprError();
@@ -1261,7 +1263,6 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
if (Tok.isNot(tok::r_paren)) {
if (ParseExpressionList(ArgExprs, CommaLocs, &Sema::CodeCompleteCall,
LHS.get())) {
- SkipUntil(tok::r_paren);
LHS = ExprError();
}
}
@@ -1424,7 +1425,7 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok,
EnterExpressionEvaluationContext Unevaluated(Actions,
Sema::Unevaluated);
Operand = ParseParenExpression(ExprType, true/*stopIfCastExpr*/,
- ParsedType(), CastTy, RParenLoc);
+ false, CastTy, RParenLoc);
CastRange = SourceRange(LParenLoc, RParenLoc);
// If ParseParenExpression parsed a '(typename)' sequence only, then this is
@@ -1717,7 +1718,7 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
ConsumeParen());
break;
}
-}
+ }
if (Res.isInvalid())
return ExprError();
@@ -1740,10 +1741,15 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
/// '(' type-name ')' '{' initializer-list ',' '}'
/// cast-expression: [C99 6.5.4]
/// '(' type-name ')' cast-expression
-///
+/// [ARC] bridged-cast-expression
+///
+/// [ARC] bridged-cast-expression:
+/// (__bridge type-name) cast-expression
+/// (__bridge_transfer type-name) cast-expression
+/// (__bridge_retained type-name) cast-expression
ExprResult
Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
- ParsedType TypeOfCast, ParsedType &CastTy,
+ bool isTypeCast, ParsedType &CastTy,
SourceLocation &RParenLoc) {
assert(Tok.is(tok::l_paren) && "Not a paren expr!");
GreaterThanIsOperatorScope G(GreaterThanIsOperator, true);
@@ -1772,7 +1778,43 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
// If the substmt parsed correctly, build the AST node.
if (!Stmt.isInvalid())
Result = Actions.ActOnStmtExpr(OpenLoc, Stmt.take(), Tok.getLocation());
-
+ } else if (ExprType >= CompoundLiteral &&
+ (Tok.is(tok::kw___bridge) ||
+ Tok.is(tok::kw___bridge_transfer) ||
+ Tok.is(tok::kw___bridge_retained) ||
+ Tok.is(tok::kw___bridge_retain))) {
+ tok::TokenKind tokenKind = Tok.getKind();
+ SourceLocation BridgeKeywordLoc = ConsumeToken();
+
+ // Parse an Objective-C ARC ownership cast expression.
+ ObjCBridgeCastKind Kind;
+ if (tokenKind == tok::kw___bridge)
+ Kind = OBC_Bridge;
+ else if (tokenKind == tok::kw___bridge_transfer)
+ Kind = OBC_BridgeTransfer;
+ else if (tokenKind == tok::kw___bridge_retained)
+ Kind = OBC_BridgeRetained;
+ else {
+ // As a hopefully temporary workaround, allow __bridge_retain as
+ // a synonym for __bridge_retained, but only in system headers.
+ assert(tokenKind == tok::kw___bridge_retain);
+ Kind = OBC_BridgeRetained;
+ if (!PP.getSourceManager().isInSystemHeader(BridgeKeywordLoc))
+ Diag(BridgeKeywordLoc, diag::err_arc_bridge_retain)
+ << FixItHint::CreateReplacement(BridgeKeywordLoc,
+ "__bridge_retained");
+ }
+
+ TypeResult Ty = ParseTypeName();
+ SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, OpenLoc);
+ ExprResult SubExpr = ParseCastExpression(/*isUnaryExpression=*/false);
+
+ if (Ty.isInvalid() || SubExpr.isInvalid())
+ return ExprError();
+
+ return Actions.ActOnObjCBridgedCast(getCurScope(), OpenLoc, Kind,
+ BridgeKeywordLoc, Ty.get(),
+ RParenLoc, SubExpr.get());
} else if (ExprType >= CompoundLiteral &&
isTypeIdInParens(isAmbiguousTypeId)) {
@@ -1787,20 +1829,23 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
return ParseCXXAmbiguousParenExpression(ExprType, CastTy,
OpenLoc, RParenLoc);
- TypeResult Ty;
-
- {
- InMessageExpressionRAIIObject InMessage(*this, false);
- Ty = ParseTypeName();
- }
+ // Parse the type declarator.
+ DeclSpec DS(AttrFactory);
+ ParseSpecifierQualifierList(DS);
+ Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
+ ParseDeclarator(DeclaratorInfo);
// If our type is followed by an identifier and either ':' or ']', then
// this is probably an Objective-C message send where the leading '[' is
// missing. Recover as if that were the case.
- if (!Ty.isInvalid() && Tok.is(tok::identifier) && !InMessageExpression &&
- getLang().ObjC1 && !Ty.get().get().isNull() &&
- (NextToken().is(tok::colon) || NextToken().is(tok::r_square)) &&
- Ty.get().get()->isObjCObjectOrInterfaceType()) {
+ if (!DeclaratorInfo.isInvalidType() && Tok.is(tok::identifier) &&
+ !InMessageExpression && getLang().ObjC1 &&
+ (NextToken().is(tok::colon) || NextToken().is(tok::r_square))) {
+ TypeResult Ty;
+ {
+ InMessageExpressionRAIIObject InMessage(*this, false);
+ Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
+ }
Result = ParseObjCMessageExpressionBody(SourceLocation(),
SourceLocation(),
Ty.get(), 0);
@@ -1813,21 +1858,31 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
if (Tok.is(tok::l_brace)) {
ExprType = CompoundLiteral;
+ TypeResult Ty;
+ {
+ InMessageExpressionRAIIObject InMessage(*this, false);
+ Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
+ }
return ParseCompoundLiteralExpression(Ty.get(), OpenLoc, RParenLoc);
}
if (ExprType == CastExpr) {
// We parsed '(' type-name ')' and the thing after it wasn't a '{'.
- if (Ty.isInvalid())
+ if (DeclaratorInfo.isInvalidType())
return ExprError();
- CastTy = Ty.get();
-
// Note that this doesn't parse the subsequent cast-expression, it just
// returns the parsed type to the callee.
- if (stopIfCastExpr)
+ if (stopIfCastExpr) {
+ TypeResult Ty;
+ {
+ InMessageExpressionRAIIObject InMessage(*this, false);
+ Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
+ }
+ CastTy = Ty.get();
return ExprResult();
+ }
// Reject the cast of super idiom in ObjC.
if (Tok.is(tok::identifier) && getLang().ObjC1 &&
@@ -1841,17 +1896,21 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
// Parse the cast-expression that follows it next.
// TODO: For cast expression with CastTy.
- Result = ParseCastExpression(false, false, CastTy);
- if (!Result.isInvalid())
- Result = Actions.ActOnCastExpr(getCurScope(), OpenLoc, CastTy,
+ Result = ParseCastExpression(/*isUnaryExpression=*/false,
+ /*isAddressOfOperand=*/false,
+ /*isTypeCast=*/true);
+ if (!Result.isInvalid()) {
+ Result = Actions.ActOnCastExpr(getCurScope(), OpenLoc,
+ DeclaratorInfo, CastTy,
RParenLoc, Result.take());
+ }
return move(Result);
}
Diag(Tok, diag::err_expected_lbrace_in_compound_literal);
return ExprError();
}
- } else if (TypeOfCast) {
+ } else if (isTypeCast) {
// Parse the expression-list.
InMessageExpressionRAIIObject InMessage(*this, false);
@@ -1861,7 +1920,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
if (!ParseExpressionList(ArgExprs, CommaLocs)) {
ExprType = SimpleExpr;
Result = Actions.ActOnParenOrParenListExpr(OpenLoc, Tok.getLocation(),
- move_arg(ArgExprs), TypeOfCast);
+ move_arg(ArgExprs));
}
} else {
InMessageExpressionRAIIObject InMessage(*this, false);
@@ -2174,6 +2233,7 @@ ExprResult Parser::ParseBlockLiteralExpression() {
SourceLocation(),
0, 0, 0,
true, SourceLocation(),
+ SourceLocation(),
EST_None,
SourceLocation(),
0, 0, 0, 0,
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index eab7114284de..b32eeda24279 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -245,8 +245,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
// So we need to check whether the simple-template-id is of the
// right kind (it should name a type or be dependent), and then
// convert it into a type within the nested-name-specifier.
- TemplateIdAnnotation *TemplateId
- = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+ TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde)) {
*MayBePseudoDestructor = true;
return false;
@@ -281,10 +280,6 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
SS.SetInvalid(SourceRange(StartLoc, CCLoc));
}
- // If we are caching tokens we will process the TemplateId again,
- // otherwise destroy it.
- if (!PP.isBacktrackEnabled())
- TemplateId->Destroy();
continue;
}
@@ -543,7 +538,14 @@ ExprResult Parser::ParseCXXCasts() {
if (ExpectAndConsume(tok::less, diag::err_expected_less_after, CastName))
return ExprError();
- TypeResult CastTy = ParseTypeName();
+ // Parse the common declaration-specifiers piece.
+ DeclSpec DS(AttrFactory);
+ ParseSpecifierQualifierList(DS);
+
+ // Parse the abstract-declarator, if present.
+ Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
+ ParseDeclarator(DeclaratorInfo);
+
SourceLocation RAngleBracketLoc = Tok.getLocation();
if (ExpectAndConsume(tok::greater, diag::err_expected_greater))
@@ -559,9 +561,9 @@ ExprResult Parser::ParseCXXCasts() {
// Match the ')'.
RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
- if (!Result.isInvalid() && !CastTy.isInvalid())
+ if (!Result.isInvalid() && !DeclaratorInfo.isInvalidType())
Result = Actions.ActOnCXXNamedCast(OpLoc, Kind,
- LAngleBracketLoc, CastTy.get(),
+ LAngleBracketLoc, DeclaratorInfo,
RAngleBracketLoc,
LParenLoc, Result.take(), RParenLoc);
@@ -785,12 +787,12 @@ ExprResult Parser::ParseThrowExpression() {
case tok::r_brace:
case tok::colon:
case tok::comma:
- return Actions.ActOnCXXThrow(ThrowLoc, 0);
+ return Actions.ActOnCXXThrow(getCurScope(), ThrowLoc, 0);
default:
ExprResult Expr(ParseAssignmentExpression());
if (Expr.isInvalid()) return move(Expr);
- return Actions.ActOnCXXThrow(ThrowLoc, Expr.take());
+ return Actions.ActOnCXXThrow(getCurScope(), ThrowLoc, Expr.take());
}
}
@@ -1606,8 +1608,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
// unqualified-id:
// template-id (already parsed and annotated)
if (Tok.is(tok::annot_template_id)) {
- TemplateIdAnnotation *TemplateId
- = static_cast<TemplateIdAnnotation*>(Tok.getAnnotationValue());
+ TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
// If the template-name names the current class, then this is a constructor
if (AllowConstructorName && TemplateId->Name &&
@@ -1630,7 +1631,6 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
/*NontrivialTypeSourceInfo=*/true),
TemplateId->TemplateNameLoc,
TemplateId->RAngleLoc);
- TemplateId->Destroy();
ConsumeToken();
return false;
}
@@ -1755,7 +1755,7 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
SourceRange TypeIdParens;
DeclSpec DS(AttrFactory);
- Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
+ Declarator DeclaratorInfo(DS, Declarator::CXXNewContext);
if (Tok.is(tok::l_paren)) {
// If it turns out to be a placement, we change the type location.
PlacementLParen = ConsumeParen();
@@ -2200,7 +2200,8 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
Result = ParseCastExpression(false/*isUnaryExpression*/,
false/*isAddressofOperand*/,
NotCastExpr,
- ParsedType()/*TypeOfCast*/);
+ // type-id has priority.
+ true/*isTypeCast*/);
}
// If we parsed a cast-expression, it's really a type-id, otherwise it's
@@ -2219,7 +2220,11 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
ConsumeAnyToken();
if (ParseAs >= CompoundLiteral) {
- TypeResult Ty = ParseTypeName();
+ // Parse the type declarator.
+ DeclSpec DS(AttrFactory);
+ ParseSpecifierQualifierList(DS);
+ Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
+ ParseDeclarator(DeclaratorInfo);
// Match the ')'.
if (Tok.is(tok::r_paren))
@@ -2229,21 +2234,21 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
if (ParseAs == CompoundLiteral) {
ExprType = CompoundLiteral;
+ TypeResult Ty = ParseTypeName();
return ParseCompoundLiteralExpression(Ty.get(), LParenLoc, RParenLoc);
}
// We parsed '(' type-id ')' and the thing after it wasn't a '{'.
assert(ParseAs == CastExpr);
- if (Ty.isInvalid())
+ if (DeclaratorInfo.isInvalidType())
return ExprError();
- CastTy = Ty.get();
-
// Result is what ParseCastExpression returned earlier.
if (!Result.isInvalid())
- Result = Actions.ActOnCastExpr(getCurScope(), LParenLoc, CastTy, RParenLoc,
- Result.take());
+ Result = Actions.ActOnCastExpr(getCurScope(), LParenLoc,
+ DeclaratorInfo, CastTy,
+ RParenLoc, Result.take());
return move(Result);
}
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index a8c18c01a291..7641565d1cc3 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -480,6 +480,10 @@ void Parser::ParseObjCInterfaceDeclList(Decl *interfaceDecl,
/// retain
/// copy
/// nonatomic
+/// atomic
+/// strong
+/// weak
+/// unsafe_unretained
///
void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS, Decl *ClassDecl) {
assert(Tok.getKind() == tok::l_paren);
@@ -504,16 +508,22 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS, Decl *ClassDecl) {
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_readonly);
else if (II->isStr("assign"))
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_assign);
+ else if (II->isStr("unsafe_unretained"))
+ DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_unsafe_unretained);
else if (II->isStr("readwrite"))
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_readwrite);
else if (II->isStr("retain"))
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_retain);
+ else if (II->isStr("strong"))
+ DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_strong);
else if (II->isStr("copy"))
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_copy);
else if (II->isStr("nonatomic"))
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_nonatomic);
else if (II->isStr("atomic"))
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_atomic);
+ else if (II->isStr("weak"))
+ DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_weak);
else if (II->isStr("getter") || II->isStr("setter")) {
bool IsSetter = II->getNameStart()[0] == 's';
@@ -775,11 +785,12 @@ ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS,
ParsedType Ty;
if (isTypeSpecifierQualifier()) {
- TypeResult TypeSpec = ParseTypeName(0, Declarator::ObjCPrototypeContext);
+ TypeResult TypeSpec =
+ ParseTypeName(0, Declarator::ObjCPrototypeContext, &DS);
if (!TypeSpec.isInvalid())
Ty = TypeSpec.get();
}
-
+
if (Tok.is(tok::r_paren))
ConsumeParen();
else if (Tok.getLocation() == TypeStartLoc) {
@@ -1622,10 +1633,7 @@ StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
if (Tok.isNot(tok::ellipsis)) {
DeclSpec DS(AttrFactory);
ParseDeclarationSpecifiers(DS);
- // For some odd reason, the name of the exception variable is
- // optional. As a result, we need to use "PrototypeContext", because
- // we must accept either 'declarator' or 'abstract-declarator' here.
- Declarator ParmDecl(DS, Declarator::PrototypeContext);
+ Declarator ParmDecl(DS, Declarator::ObjCCatchContext);
ParseDeclarator(ParmDecl);
// Inform the actions module about the declarator, so it
@@ -1690,6 +1698,29 @@ StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
FinallyStmt.take());
}
+/// objc-autoreleasepool-statement:
+/// @autoreleasepool compound-statement
+///
+StmtResult
+Parser::ParseObjCAutoreleasePoolStmt(SourceLocation atLoc) {
+ ConsumeToken(); // consume autoreleasepool
+ if (Tok.isNot(tok::l_brace)) {
+ Diag(Tok, diag::err_expected_lbrace);
+ return StmtError();
+ }
+ // Enter a scope to hold everything within the compound stmt. Compound
+ // statements can always hold declarations.
+ ParseScope BodyScope(this, Scope::DeclScope);
+
+ StmtResult AutoreleasePoolBody(ParseCompoundStatementBody());
+
+ BodyScope.Exit();
+ if (AutoreleasePoolBody.isInvalid())
+ AutoreleasePoolBody = Actions.ActOnNullStmt(Tok.getLocation());
+ return Actions.ActOnObjCAutoreleasePoolStmt(atLoc,
+ AutoreleasePoolBody.take());
+}
+
/// objc-method-def: objc-method-proto ';'[opt] '{' body '}'
///
Decl *Parser::ParseObjCMethodDefinition() {
@@ -1765,6 +1796,9 @@ StmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc) {
if (Tok.isObjCAtKeyword(tok::objc_synchronized))
return ParseObjCSynchronizedStmt(AtLoc);
+
+ if (Tok.isObjCAtKeyword(tok::objc_autoreleasepool))
+ return ParseObjCAutoreleasePoolStmt(AtLoc);
ExprResult Res(ParseExpressionWithLeadingAt(AtLoc));
if (Res.isInvalid()) {
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index 6cc8b57b61fe..b91bca55a9dc 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -226,7 +226,7 @@ Retry:
case tok::semi: { // C99 6.8.3p3: expression[opt] ';'
SourceLocation LeadingEmptyMacroLoc;
if (Tok.hasLeadingEmptyMacro())
- LeadingEmptyMacroLoc = PP.getLastEmptyMacroInstantiationLoc();
+ LeadingEmptyMacroLoc = PP.getLastEmptyMacroExpansionLoc();
return Actions.ActOnNullStmt(ConsumeToken(), LeadingEmptyMacroLoc);
}
@@ -502,6 +502,7 @@ StmtResult Parser::ParseCaseStatement(ParsedAttributes &attrs, bool MissingCase,
StmtTy *DeepestParsedCaseStmt = 0;
// While we have case statements, eat and stack them.
+ SourceLocation ColonLoc;
do {
SourceLocation CaseLoc = MissingCase ? Expr.get()->getExprLoc() :
ConsumeToken(); // eat the 'case'.
@@ -539,7 +540,6 @@ StmtResult Parser::ParseCaseStatement(ParsedAttributes &attrs, bool MissingCase,
ColonProtection.restore();
- SourceLocation ColonLoc;
if (Tok.is(tok::colon)) {
ColonLoc = ConsumeToken();
@@ -589,8 +589,8 @@ StmtResult Parser::ParseCaseStatement(ParsedAttributes &attrs, bool MissingCase,
} else {
// Nicely diagnose the common error "switch (X) { case 4: }", which is
// not valid.
- // FIXME: add insertion hint.
- Diag(Tok, diag::err_label_end_of_compound_statement);
+ SourceLocation AfterColonLoc = PP.getLocForEndOfToken(ColonLoc);
+ Diag(AfterColonLoc, diag::err_label_end_of_compound_statement);
SubStmt = true;
}
@@ -634,7 +634,8 @@ StmtResult Parser::ParseDefaultStatement(ParsedAttributes &attrs) {
// Diagnose the common error "switch (X) {... default: }", which is not valid.
if (Tok.is(tok::r_brace)) {
- Diag(Tok, diag::err_label_end_of_compound_statement);
+ SourceLocation AfterColonLoc = PP.getLocForEndOfToken(ColonLoc);
+ Diag(AfterColonLoc, diag::err_label_end_of_compound_statement);
return StmtError();
}
@@ -646,6 +647,10 @@ StmtResult Parser::ParseDefaultStatement(ParsedAttributes &attrs) {
SubStmt.get(), getCurScope());
}
+StmtResult Parser::ParseCompoundStatement(ParsedAttributes &Attr,
+ bool isStmtExpr) {
+ return ParseCompoundStatement(Attr, isStmtExpr, Scope::DeclScope);
+}
/// ParseCompoundStatement - Parse a "{}" block.
///
@@ -675,14 +680,15 @@ StmtResult Parser::ParseDefaultStatement(ParsedAttributes &attrs) {
/// [OMP] flush-directive
///
StmtResult Parser::ParseCompoundStatement(ParsedAttributes &attrs,
- bool isStmtExpr) {
+ bool isStmtExpr,
+ unsigned ScopeFlags) {
//FIXME: Use attributes?
assert(Tok.is(tok::l_brace) && "Not a compount stmt!");
// Enter a scope to hold everything within the compound stmt. Compound
// statements can always hold declarations.
- ParseScope CompoundScope(this, Scope::DeclScope);
+ ParseScope CompoundScope(this, ScopeFlags);
// Parse the statements in the body.
return ParseCompoundStatementBody(isStmtExpr);
@@ -1909,7 +1915,8 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) {
return StmtError(Diag(Tok, diag::err_expected_lbrace));
// FIXME: Possible draft standard bug: attribute-specifier should be allowed?
ParsedAttributesWithRange attrs(AttrFactory);
- StmtResult TryBlock(ParseCompoundStatement(attrs));
+ StmtResult TryBlock(ParseCompoundStatement(attrs, /*isStmtExpr=*/false,
+ Scope::DeclScope|Scope::TryScope));
if (TryBlock.isInvalid())
return move(TryBlock);
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index aa89d75c6d1b..9eab40a3ecdf 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -861,8 +861,7 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
void Parser::AnnotateTemplateIdTokenAsType() {
assert(Tok.is(tok::annot_template_id) && "Requires template-id tokens");
- TemplateIdAnnotation *TemplateId
- = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+ TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
assert((TemplateId->Kind == TNK_Type_template ||
TemplateId->Kind == TNK_Dependent_template_name) &&
"Only works for type and dependent templates");
@@ -888,7 +887,6 @@ void Parser::AnnotateTemplateIdTokenAsType() {
// Replace the template-id annotation token, and possible the scope-specifier
// that precedes it, with the typename annotation token.
PP.AnnotateCachedTokens(Tok);
- TemplateId->Destroy();
}
/// \brief Determine whether the given token can end a template argument.
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index 78d2c9091b1b..2ba0fc673f67 100644
--- a/lib/Parse/ParseTentative.cpp
+++ b/lib/Parse/ParseTentative.cpp
@@ -908,8 +908,7 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
return TPResult::True();
case tok::annot_template_id: {
- TemplateIdAnnotation *TemplateId
- = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+ TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
if (TemplateId->Kind != TNK_Type_template)
return TPResult::False();
CXXScopeSpec SS;
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index f19472ccdc04..5c502907bc15 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -124,9 +124,8 @@ void Parser::SuggestParentheses(SourceLocation Loc, unsigned DK,
/// 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.
+/// present. If not present, it emits a corresponding diagnostic indicating
+/// that the parser failed to match the RHS of the token at LHSLoc.
SourceLocation Parser::MatchRHSPunctuation(tok::TokenKind RHSTok,
SourceLocation LHSLoc) {
@@ -486,6 +485,7 @@ void Parser::Initialize() {
/// ParseTopLevelDecl - Parse one top-level declaration, return whatever the
/// action tells us to. This returns true if the EOF was encountered.
bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) {
+ DelayedCleanupPoint CleanupRAII(TopLevelDeclCleanupPool);
while (Tok.is(tok::annot_pragma_unused))
HandlePragmaUnused();
@@ -548,6 +548,7 @@ void Parser::ParseTranslationUnit() {
Parser::DeclGroupPtrTy
Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
ParsingDeclSpec *DS) {
+ DelayedCleanupPoint CleanupRAII(TopLevelDeclCleanupPool);
ParenBraceBracketBalancer BalancerRAIIObj(*this);
Decl *SingleDecl = 0;
@@ -1155,6 +1156,18 @@ Parser::ExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) {
return move(Result);
}
+/// \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 *Parser::takeTemplateIdAnnotation(const Token &tok) {
+ assert(tok.is(tok::annot_template_id) && "Expected template-id token");
+ TemplateIdAnnotation *
+ Id = static_cast<TemplateIdAnnotation *>(tok.getAnnotationValue());
+ TopLevelDeclCleanupPool.delayMemberFunc< TemplateIdAnnotation,
+ &TemplateIdAnnotation::Destroy>(Id);
+ return Id;
+}
+
/// 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
@@ -1209,8 +1222,7 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) {
*Tok.getIdentifierInfo(),
Tok.getLocation());
} else if (Tok.is(tok::annot_template_id)) {
- TemplateIdAnnotation *TemplateId
- = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+ TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
if (TemplateId->Kind == TNK_Function_template) {
Diag(Tok, diag::err_typename_refers_to_non_type_template)
<< Tok.getAnnotationRange();
@@ -1228,7 +1240,6 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) {
TemplateId->LAngleLoc,
TemplateArgsPtr,
TemplateId->RAngleLoc);
- TemplateId->Destroy();
} else {
Diag(Tok, diag::err_expected_type_name_after_typename)
<< SS.getRange();
@@ -1311,8 +1322,7 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) {
}
if (Tok.is(tok::annot_template_id)) {
- TemplateIdAnnotation *TemplateId
- = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+ TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
if (TemplateId->Kind == TNK_Type_template) {
// A template-id that refers to a type was parsed into a
// template-id annotation in a context where we weren't allowed
diff --git a/lib/Rewrite/FixItRewriter.cpp b/lib/Rewrite/FixItRewriter.cpp
index 8dcc5dcba789..e50793e2775f 100644
--- a/lib/Rewrite/FixItRewriter.cpp
+++ b/lib/Rewrite/FixItRewriter.cpp
@@ -121,8 +121,7 @@ void FixItRewriter::HandleDiagnostic(Diagnostic::Level DiagLevel,
if (Hint.CodeToInsert.empty()) {
// We're removing code.
- if (Rewrite.RemoveText(Hint.RemoveRange.getBegin(),
- Rewrite.getRangeSize(Hint.RemoveRange)))
+ if (Rewrite.RemoveText(Hint.RemoveRange))
Failed = true;
continue;
}
diff --git a/lib/Rewrite/HTMLRewrite.cpp b/lib/Rewrite/HTMLRewrite.cpp
index df08cd7cbf3d..0b54755dc58c 100644
--- a/lib/Rewrite/HTMLRewrite.cpp
+++ b/lib/Rewrite/HTMLRewrite.cpp
@@ -516,7 +516,7 @@ void html::HighlightMacros(Rewriter &R, FileID FID, const Preprocessor& PP) {
}
// Okay, we have the first token of a macro expansion: highlight the
- // instantiation by inserting a start tag before the macro instantiation and
+ // expansion by inserting a start tag before the macro expansion and
// end tag after it.
std::pair<SourceLocation, SourceLocation> LLoc =
SM.getInstantiationRange(Tok.getLocation());
diff --git a/lib/Rewrite/RewriteObjC.cpp b/lib/Rewrite/RewriteObjC.cpp
index 8cdb55a0c1c6..8202164ebce5 100644
--- a/lib/Rewrite/RewriteObjC.cpp
+++ b/lib/Rewrite/RewriteObjC.cpp
@@ -2110,8 +2110,7 @@ Stmt *RewriteObjC::RewriteAtEncode(ObjCEncodeExpr *Exp) {
QualType StrType = Context->getPointerType(Context->CharTy);
std::string StrEncoding;
Context->getObjCEncodingForType(Exp->getEncodedType(), StrEncoding);
- Expr *Replacement = StringLiteral::Create(*Context,StrEncoding.c_str(),
- StrEncoding.length(),
+ Expr *Replacement = StringLiteral::Create(*Context, StrEncoding,
false, false, StrType,
SourceLocation());
ReplaceStmt(Exp, Replacement);
@@ -2129,9 +2128,8 @@ Stmt *RewriteObjC::RewriteAtSelector(ObjCSelectorExpr *Exp) {
llvm::SmallVector<Expr*, 8> SelExprs;
QualType argType = Context->getPointerType(Context->CharTy);
SelExprs.push_back(StringLiteral::Create(*Context,
- Exp->getSelector().getAsString().c_str(),
- Exp->getSelector().getAsString().size(),
- false, false, argType,
+ Exp->getSelector().getAsString(),
+ false, false, argType,
SourceLocation()));
CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl,
&SelExprs[0], SelExprs.size());
@@ -2798,8 +2796,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
llvm::SmallVector<Expr*, 8> ClsExprs;
QualType argType = Context->getPointerType(Context->CharTy);
ClsExprs.push_back(StringLiteral::Create(*Context,
- ClassDecl->getIdentifier()->getNameStart(),
- ClassDecl->getIdentifier()->getLength(),
+ ClassDecl->getIdentifier()->getName(),
false, false, argType, SourceLocation()));
CallExpr *Cls = SynthesizeCallToFunctionDecl(GetMetaClassFunctionDecl,
&ClsExprs[0],
@@ -2877,8 +2874,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
= Exp->getClassReceiver()->getAs<ObjCObjectType>()->getInterface();
IdentifierInfo *clsName = Class->getIdentifier();
ClsExprs.push_back(StringLiteral::Create(*Context,
- clsName->getNameStart(),
- clsName->getLength(),
+ clsName->getName(),
false, false,
argType, SourceLocation()));
CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
@@ -2909,8 +2905,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
llvm::SmallVector<Expr*, 8> ClsExprs;
QualType argType = Context->getPointerType(Context->CharTy);
ClsExprs.push_back(StringLiteral::Create(*Context,
- ClassDecl->getIdentifier()->getNameStart(),
- ClassDecl->getIdentifier()->getLength(),
+ ClassDecl->getIdentifier()->getName(),
false, false, argType, SourceLocation()));
CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
&ClsExprs[0],
@@ -2991,8 +2986,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
llvm::SmallVector<Expr*, 8> SelExprs;
QualType argType = Context->getPointerType(Context->CharTy);
SelExprs.push_back(StringLiteral::Create(*Context,
- Exp->getSelector().getAsString().c_str(),
- Exp->getSelector().getAsString().size(),
+ Exp->getSelector().getAsString(),
false, false, argType, SourceLocation()));
CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl,
&SelExprs[0], SelExprs.size(),
diff --git a/lib/Rewrite/Rewriter.cpp b/lib/Rewrite/Rewriter.cpp
index 51fe379fee0d..92f516074ec9 100644
--- a/lib/Rewrite/Rewriter.cpp
+++ b/lib/Rewrite/Rewriter.cpp
@@ -231,10 +231,44 @@ RewriteBuffer &Rewriter::getEditBuffer(FileID FID) {
/// InsertText - Insert the specified string at the specified location in the
/// original buffer.
bool Rewriter::InsertText(SourceLocation Loc, llvm::StringRef Str,
- bool InsertAfter) {
+ bool InsertAfter, bool indentNewLines) {
+ using llvm::StringRef;
+
if (!isRewritable(Loc)) return true;
FileID FID;
unsigned StartOffs = getLocationOffsetAndFileID(Loc, FID);
+
+ llvm::SmallString<128> indentedStr;
+ if (indentNewLines && Str.find('\n') != StringRef::npos) {
+ StringRef MB = SourceMgr->getBufferData(FID);
+
+ unsigned lineNo = SourceMgr->getLineNumber(FID, StartOffs) - 1;
+ const SrcMgr::ContentCache *
+ Content = SourceMgr->getSLocEntry(FID).getFile().getContentCache();
+ unsigned lineOffs = Content->SourceLineCache[lineNo];
+
+ // Find the whitespace at the start of the line.
+ StringRef indentSpace;
+ {
+ unsigned i = lineOffs;
+ while (isWhitespace(MB[i]))
+ ++i;
+ indentSpace = MB.substr(lineOffs, i-lineOffs);
+ }
+
+ llvm::SmallVector<StringRef, 4> lines;
+ Str.split(lines, "\n");
+
+ for (unsigned i = 0, e = lines.size(); i != e; ++i) {
+ indentedStr += lines[i];
+ if (i < e-1) {
+ indentedStr += '\n';
+ indentedStr += indentSpace;
+ }
+ }
+ Str = indentedStr.str();
+ }
+
getEditBuffer(FID).InsertText(StartOffs, Str, InsertAfter);
return false;
}
@@ -317,6 +351,7 @@ bool Rewriter::IncreaseIndentation(CharSourceRange range,
SourceLocation parentIndent) {
using llvm::StringRef;
+ if (range.isInvalid()) return true;
if (!isRewritable(range.getBegin())) return true;
if (!isRewritable(range.getEnd())) return true;
if (!isRewritable(parentIndent)) return true;
@@ -330,7 +365,7 @@ bool Rewriter::IncreaseIndentation(CharSourceRange range,
if (StartFileID != EndFileID || StartFileID != parentFileID)
return true;
- if (StartOff >= EndOff || parentOff >= StartOff)
+ if (StartOff > EndOff)
return true;
FileID FID = StartFileID;
@@ -343,16 +378,12 @@ bool Rewriter::IncreaseIndentation(CharSourceRange range,
const SrcMgr::ContentCache *
Content = SourceMgr->getSLocEntry(FID).getFile().getContentCache();
- // Find where the line starts for the three offsets.
+ // Find where the lines start.
unsigned parentLineOffs = Content->SourceLineCache[parentLineNo];
unsigned startLineOffs = Content->SourceLineCache[startLineNo];
- unsigned endLineOffs = Content->SourceLineCache[endLineNo];
-
- if (startLineOffs == endLineOffs || startLineOffs == parentLineOffs)
- return true;
// Find the whitespace at the start of each line.
- StringRef parentSpace, startSpace, endSpace;
+ StringRef parentSpace, startSpace;
{
unsigned i = parentLineOffs;
while (isWhitespace(MB[i]))
@@ -363,11 +394,6 @@ bool Rewriter::IncreaseIndentation(CharSourceRange range,
while (isWhitespace(MB[i]))
++i;
startSpace = MB.substr(startLineOffs, i-startLineOffs);
-
- i = endLineOffs;
- while (isWhitespace(MB[i]))
- ++i;
- endSpace = MB.substr(endLineOffs, i-endLineOffs);
}
if (parentSpace.size() >= startSpace.size())
return true;
@@ -378,19 +404,14 @@ bool Rewriter::IncreaseIndentation(CharSourceRange range,
// Indent the lines between start/end offsets.
RewriteBuffer &RB = getEditBuffer(FID);
- for (unsigned i = startLineOffs; i != endLineOffs; ++i) {
- if (MB[i] == '\n') {
- unsigned startOfLine = i+1;
- if (startOfLine == endLineOffs)
- break;
- StringRef origIndent;
- unsigned ws = startOfLine;
- while (isWhitespace(MB[ws]))
- ++ws;
- origIndent = MB.substr(startOfLine, ws-startOfLine);
- if (origIndent.startswith(startSpace))
- RB.InsertText(startOfLine, indent, /*InsertAfter=*/false);
- }
+ for (unsigned lineNo = startLineNo; lineNo <= endLineNo; ++lineNo) {
+ unsigned offs = Content->SourceLineCache[lineNo];
+ unsigned i = offs;
+ while (isWhitespace(MB[i]))
+ ++i;
+ StringRef origIndent = MB.substr(offs, i-offs);
+ if (origIndent.startswith(startSpace))
+ RB.InsertText(offs, indent, /*InsertAfter=*/false);
}
return false;
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
index 9efae6103a4a..7a14855e69cd 100644
--- a/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/lib/Sema/AnalysisBasedWarnings.cpp
@@ -486,7 +486,8 @@ static void SuggestInitializationFixit(Sema &S, const VarDecl *VD) {
const char *initialization = 0;
QualType VariableTy = VD->getType().getCanonicalType();
- if (VariableTy->getAs<ObjCObjectPointerType>()) {
+ if (VariableTy->isObjCObjectPointerType() ||
+ VariableTy->isBlockPointerType()) {
// Check if 'nil' is defined.
if (S.PP.getMacroInfo(&S.getASTContext().Idents.get("nil")))
initialization = " = nil";
@@ -499,6 +500,13 @@ static void SuggestInitializationFixit(Sema &S, const VarDecl *VD) {
initialization = " = false";
else if (VariableTy->isEnumeralType())
return;
+ else if (VariableTy->isPointerType() || VariableTy->isMemberPointerType()) {
+ // Check if 'NULL' is defined.
+ if (S.PP.getMacroInfo(&S.getASTContext().Idents.get("NULL")))
+ initialization = " = NULL";
+ else
+ initialization = " = 0";
+ }
else if (VariableTy->isScalarType())
initialization = " = 0";
@@ -589,7 +597,17 @@ clang::sema::AnalysisBasedWarnings::Policy::Policy() {
enableCheckUnreachable = 0;
}
-clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s) : S(s) {
+clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s)
+ : S(s),
+ NumFunctionsAnalyzed(0),
+ NumFunctionsWithBadCFGs(0),
+ NumCFGBlocks(0),
+ MaxCFGBlocksPerFunction(0),
+ NumUninitAnalysisFunctions(0),
+ NumUninitAnalysisVariables(0),
+ MaxUninitAnalysisVariablesPerFunction(0),
+ NumUninitAnalysisBlockVisits(0),
+ MaxUninitAnalysisBlockVisitsPerFunction(0) {
Diagnostic &D = S.getDiagnostics();
DefaultPolicy.enableCheckUnreachable = (unsigned)
(D.getDiagnosticLevel(diag::warn_unreachable, SourceLocation()) !=
@@ -705,8 +723,68 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
!= Diagnostic::Ignored) {
if (CFG *cfg = AC.getCFG()) {
UninitValsDiagReporter reporter(S);
+ UninitVariablesAnalysisStats stats;
+ std::memset(&stats, 0, sizeof(UninitVariablesAnalysisStats));
runUninitializedVariablesAnalysis(*cast<DeclContext>(D), *cfg, AC,
- reporter);
+ reporter, stats);
+
+ if (S.CollectStats && stats.NumVariablesAnalyzed > 0) {
+ ++NumUninitAnalysisFunctions;
+ NumUninitAnalysisVariables += stats.NumVariablesAnalyzed;
+ NumUninitAnalysisBlockVisits += stats.NumBlockVisits;
+ MaxUninitAnalysisVariablesPerFunction =
+ std::max(MaxUninitAnalysisVariablesPerFunction,
+ stats.NumVariablesAnalyzed);
+ MaxUninitAnalysisBlockVisitsPerFunction =
+ std::max(MaxUninitAnalysisBlockVisitsPerFunction,
+ stats.NumBlockVisits);
+ }
}
}
+
+ // Collect statistics about the CFG if it was built.
+ if (S.CollectStats && AC.isCFGBuilt()) {
+ ++NumFunctionsAnalyzed;
+ if (CFG *cfg = AC.getCFG()) {
+ // If we successfully built a CFG for this context, record some more
+ // detail information about it.
+ NumCFGBlocks += cfg->getNumBlockIDs();
+ MaxCFGBlocksPerFunction = std::max(MaxCFGBlocksPerFunction,
+ cfg->getNumBlockIDs());
+ } else {
+ ++NumFunctionsWithBadCFGs;
+ }
+ }
+}
+
+void clang::sema::AnalysisBasedWarnings::PrintStats() const {
+ llvm::errs() << "\n*** Analysis Based Warnings Stats:\n";
+
+ unsigned NumCFGsBuilt = NumFunctionsAnalyzed - NumFunctionsWithBadCFGs;
+ unsigned AvgCFGBlocksPerFunction =
+ !NumCFGsBuilt ? 0 : NumCFGBlocks/NumCFGsBuilt;
+ llvm::errs() << NumFunctionsAnalyzed << " functions analyzed ("
+ << NumFunctionsWithBadCFGs << " w/o CFGs).\n"
+ << " " << NumCFGBlocks << " CFG blocks built.\n"
+ << " " << AvgCFGBlocksPerFunction
+ << " average CFG blocks per function.\n"
+ << " " << MaxCFGBlocksPerFunction
+ << " max CFG blocks per function.\n";
+
+ unsigned AvgUninitVariablesPerFunction = !NumUninitAnalysisFunctions ? 0
+ : NumUninitAnalysisVariables/NumUninitAnalysisFunctions;
+ unsigned AvgUninitBlockVisitsPerFunction = !NumUninitAnalysisFunctions ? 0
+ : NumUninitAnalysisBlockVisits/NumUninitAnalysisFunctions;
+ llvm::errs() << NumUninitAnalysisFunctions
+ << " functions analyzed for uninitialiazed variables\n"
+ << " " << NumUninitAnalysisVariables << " variables analyzed.\n"
+ << " " << AvgUninitVariablesPerFunction
+ << " average variables per function.\n"
+ << " " << MaxUninitAnalysisVariablesPerFunction
+ << " max variables per function.\n"
+ << " " << NumUninitAnalysisBlockVisits << " block visits.\n"
+ << " " << AvgUninitBlockVisitsPerFunction
+ << " average block visits per function.\n"
+ << " " << MaxUninitAnalysisBlockVisitsPerFunction
+ << " max block visits per function.\n";
}
diff --git a/lib/Sema/AttributeList.cpp b/lib/Sema/AttributeList.cpp
index 619a5b961bfe..5a8330bbfd77 100644
--- a/lib/Sema/AttributeList.cpp
+++ b/lib/Sema/AttributeList.cpp
@@ -107,6 +107,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
return llvm::StringSwitch<AttributeList::Kind>(AttrName)
.Case("weak", AT_weak)
.Case("weakref", AT_weakref)
+ .Case("objc_arc_weak_reference_unavailable", AT_arc_weakref_unavailable)
.Case("pure", AT_pure)
.Case("mode", AT_mode)
.Case("used", AT_used)
@@ -177,6 +178,11 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
.Case("cf_consumed", AT_cf_consumed)
.Case("cf_returns_not_retained", AT_cf_returns_not_retained)
.Case("cf_returns_retained", AT_cf_returns_retained)
+ .Case("cf_returns_autoreleased", AT_cf_returns_autoreleased)
+ .Case("ns_consumes_self", AT_ns_consumes_self)
+ .Case("ns_consumed", AT_ns_consumed)
+ .Case("objc_ownership", AT_objc_ownership)
+ .Case("objc_precise_lifetime", AT_objc_precise_lifetime)
.Case("ownership_returns", AT_ownership_returns)
.Case("ownership_holds", AT_ownership_holds)
.Case("ownership_takes", AT_ownership_takes)
diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt
index 0a670197d7ef..652198189a4c 100644
--- a/lib/Sema/CMakeLists.txt
+++ b/lib/Sema/CMakeLists.txt
@@ -23,6 +23,7 @@ add_clang_library(clangSema
SemaExceptionSpec.cpp
SemaExpr.cpp
SemaExprCXX.cpp
+ SemaExprMember.cpp
SemaExprObjC.cpp
SemaInit.cpp
SemaLookup.cpp
diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp
index 2334ab5128a7..d7dc5b2538c6 100644
--- a/lib/Sema/CodeCompleteConsumer.cpp
+++ b/lib/Sema/CodeCompleteConsumer.cpp
@@ -46,7 +46,9 @@ bool CodeCompletionContext::wantConstructorResults() const {
case CCC_ObjCImplementation:
case CCC_ObjCIvarList:
case CCC_ClassStructUnion:
- case CCC_MemberAccess:
+ case CCC_DotMemberAccess:
+ case CCC_ArrowMemberAccess:
+ case CCC_ObjCPropertyAccess:
case CCC_EnumTag:
case CCC_UnionTag:
case CCC_ClassOrStructTag:
@@ -64,6 +66,10 @@ bool CodeCompletionContext::wantConstructorResults() const {
case CCC_TypeQualifiers:
case CCC_Other:
case CCC_OtherWithMacros:
+ case CCC_ObjCInstanceMessage:
+ case CCC_ObjCClassMessage:
+ case CCC_ObjCSuperclass:
+ case CCC_ObjCCategoryName:
return false;
}
diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp
index 5be16e7431c1..c87f2cff5489 100644
--- a/lib/Sema/DeclSpec.cpp
+++ b/lib/Sema/DeclSpec.cpp
@@ -13,8 +13,10 @@
#include "clang/Parse/ParseDiagnostic.h" // FIXME: remove this back-dependency!
#include "clang/Sema/DeclSpec.h"
+#include "clang/Sema/LocInfoType.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Expr.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Lex/Preprocessor.h"
@@ -124,6 +126,12 @@ void CXXScopeSpec::Adopt(NestedNameSpecifierLoc Other) {
Builder.Adopt(Other);
}
+SourceLocation CXXScopeSpec::getLastQualifierNameLoc() const {
+ if (!Builder.getRepresentation())
+ return SourceLocation();
+ return Builder.getTemporary().getLocalBeginLoc();
+}
+
NestedNameSpecifierLoc
CXXScopeSpec::getWithLocInContext(ASTContext &Context) const {
if (!Builder.getRepresentation())
@@ -141,6 +149,7 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic,
unsigned TypeQuals,
bool RefQualifierIsLvalueRef,
SourceLocation RefQualifierLoc,
+ SourceLocation MutableLoc,
ExceptionSpecificationType
ESpecType,
SourceLocation ESpecLoc,
@@ -166,6 +175,7 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic,
I.Fun.ArgInfo = 0;
I.Fun.RefQualifierIsLValueRef = RefQualifierIsLvalueRef;
I.Fun.RefQualifierLoc = RefQualifierLoc.getRawEncoding();
+ I.Fun.MutableLoc = MutableLoc.getRawEncoding();
I.Fun.ExceptionSpecType = ESpecType;
I.Fun.ExceptionSpecLoc = ESpecLoc.getRawEncoding();
I.Fun.NumExceptions = 0;
@@ -213,6 +223,73 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic,
return I;
}
+bool Declarator::isDeclarationOfFunction() const {
+ for (unsigned i = 0, i_end = DeclTypeInfo.size(); i < i_end; ++i) {
+ switch (DeclTypeInfo[i].Kind) {
+ case DeclaratorChunk::Function:
+ return true;
+ case DeclaratorChunk::Paren:
+ continue;
+ case DeclaratorChunk::Pointer:
+ case DeclaratorChunk::Reference:
+ case DeclaratorChunk::Array:
+ case DeclaratorChunk::BlockPointer:
+ case DeclaratorChunk::MemberPointer:
+ return false;
+ }
+ llvm_unreachable("Invalid type chunk");
+ return false;
+ }
+
+ switch (DS.getTypeSpecType()) {
+ case TST_auto:
+ case TST_bool:
+ case TST_char:
+ case TST_char16:
+ case TST_char32:
+ case TST_class:
+ case TST_decimal128:
+ case TST_decimal32:
+ case TST_decimal64:
+ case TST_double:
+ case TST_enum:
+ case TST_error:
+ case TST_float:
+ case TST_int:
+ case TST_struct:
+ case TST_union:
+ case TST_unknown_anytype:
+ case TST_unspecified:
+ case TST_void:
+ case TST_wchar:
+ return false;
+
+ case TST_decltype:
+ case TST_typeofExpr:
+ if (Expr *E = DS.getRepAsExpr())
+ return E->getType()->isFunctionType();
+ return false;
+
+ case TST_underlyingType:
+ case TST_typename:
+ case TST_typeofType: {
+ QualType QT = DS.getRepAsType().get();
+ if (QT.isNull())
+ return false;
+
+ if (const LocInfoType *LIT = dyn_cast<LocInfoType>(QT))
+ QT = LIT->getType();
+
+ if (QT.isNull())
+ return false;
+
+ return QT->isFunctionType();
+ }
+ }
+
+ return false;
+}
+
/// getParsedSpecifiers - Return a bitmask of which flavors of specifiers this
/// declaration specifier includes.
///
@@ -792,9 +869,6 @@ bool DeclSpec::isMissingDeclaratorOk() {
}
void UnqualifiedId::clear() {
- if (Kind == IK_TemplateId)
- TemplateId->Destroy();
-
Kind = IK_Identifier;
Identifier = 0;
StartLocation = SourceLocation();
diff --git a/lib/Sema/DelayedDiagnostic.cpp b/lib/Sema/DelayedDiagnostic.cpp
index af548fe13460..c6744ed80d4b 100644
--- a/lib/Sema/DelayedDiagnostic.cpp
+++ b/lib/Sema/DelayedDiagnostic.cpp
@@ -47,5 +47,8 @@ void DelayedDiagnostic::Destroy() {
case Deprecation:
delete [] DeprecationData.Message;
break;
+
+ case ForbiddenType:
+ break;
}
}
diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp
index ae154aae2062..59bc2637c8f3 100644
--- a/lib/Sema/JumpDiagnostics.cpp
+++ b/lib/Sema/JumpDiagnostics.cpp
@@ -68,7 +68,10 @@ public:
JumpScopeChecker(Stmt *Body, Sema &S);
private:
void BuildScopeInformation(Decl *D, unsigned &ParentScope);
- void BuildScopeInformation(Stmt *S, unsigned ParentScope);
+ void BuildScopeInformation(VarDecl *D, const BlockDecl *BDecl,
+ unsigned &ParentScope);
+ void BuildScopeInformation(Stmt *S, unsigned &origParentScope);
+
void VerifyJumps();
void VerifyIndirectJumps();
void DiagnoseIndirectJump(IndirectGotoStmt *IG, unsigned IGScope,
@@ -87,7 +90,8 @@ JumpScopeChecker::JumpScopeChecker(Stmt *Body, Sema &s) : S(s) {
// Build information for the top level compound statement, so that we have a
// defined scope record for every "goto" and label.
- BuildScopeInformation(Body, 0);
+ unsigned BodyParentScope = 0;
+ BuildScopeInformation(Body, BodyParentScope);
// Check that all jumps we saw are kosher.
VerifyJumps();
@@ -111,87 +115,110 @@ unsigned JumpScopeChecker::GetDeepestCommonScope(unsigned A, unsigned B) {
return A;
}
+typedef std::pair<unsigned,unsigned> ScopePair;
+
/// GetDiagForGotoScopeDecl - If this decl induces a new goto scope, return a
/// diagnostic that should be emitted if control goes over it. If not, return 0.
-static std::pair<unsigned,unsigned>
- GetDiagForGotoScopeDecl(const Decl *D, bool isCPlusPlus) {
+static ScopePair GetDiagForGotoScopeDecl(ASTContext &Context, const Decl *D) {
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
unsigned InDiag = 0, OutDiag = 0;
if (VD->getType()->isVariablyModifiedType())
InDiag = diag::note_protected_by_vla;
- if (VD->hasAttr<BlocksAttr>()) {
- InDiag = diag::note_protected_by___block;
- OutDiag = diag::note_exits___block;
- } else if (VD->hasAttr<CleanupAttr>()) {
- InDiag = diag::note_protected_by_cleanup;
- OutDiag = diag::note_exits_cleanup;
- } else if (isCPlusPlus) {
- if (!VD->hasLocalStorage())
- return std::make_pair(InDiag, OutDiag);
-
- ASTContext &Context = D->getASTContext();
- QualType T = Context.getBaseElementType(VD->getType());
- if (!T->isDependentType()) {
- // C++0x [stmt.dcl]p3:
- // A program that jumps from a point where a variable with automatic
- // storage duration is not in scope to a point where it is in scope
- // is ill-formed unless the variable has scalar type, class type with
- // a trivial default constructor and a trivial destructor, a
- // cv-qualified version of one of these types, or an array of one of
- // the preceding types and is declared without an initializer (8.5).
- // Check whether this is a C++ class.
- CXXRecordDecl *Record = T->getAsCXXRecordDecl();
-
- if (const Expr *Init = VD->getInit()) {
- bool CallsTrivialConstructor = false;
- if (Record) {
- // FIXME: With generalized initializer lists, this may
- // classify "X x{};" as having no initializer.
- if (const CXXConstructExpr *Construct
- = dyn_cast<CXXConstructExpr>(Init))
- if (const CXXConstructorDecl *Constructor
- = Construct->getConstructor())
- if ((Context.getLangOptions().CPlusPlus0x
- ? Record->hasTrivialDefaultConstructor()
- : Record->isPOD()) &&
- Constructor->isDefaultConstructor())
- CallsTrivialConstructor = true;
+ if (VD->hasAttr<BlocksAttr>())
+ return ScopePair(diag::note_protected_by___block,
+ diag::note_exits___block);
+
+ if (VD->hasAttr<CleanupAttr>())
+ return ScopePair(diag::note_protected_by_cleanup,
+ diag::note_exits_cleanup);
+
+ if (Context.getLangOptions().ObjCAutoRefCount && VD->hasLocalStorage()) {
+ switch (VD->getType().getObjCLifetime()) {
+ case Qualifiers::OCL_None:
+ case Qualifiers::OCL_ExplicitNone:
+ case Qualifiers::OCL_Autoreleasing:
+ break;
+
+ case Qualifiers::OCL_Strong:
+ case Qualifiers::OCL_Weak:
+ return ScopePair(diag::note_protected_by_objc_ownership,
+ diag::note_exits_objc_ownership);
+ }
+ }
+
+ if (Context.getLangOptions().CPlusPlus && VD->hasLocalStorage()) {
+ // C++0x [stmt.dcl]p3:
+ // A program that jumps from a point where a variable with automatic
+ // storage duration is not in scope to a point where it is in scope
+ // is ill-formed unless the variable has scalar type, class type with
+ // a trivial default constructor and a trivial destructor, a
+ // cv-qualified version of one of these types, or an array of one of
+ // the preceding types and is declared without an initializer.
+
+ // C++03 [stmt.dcl.p3:
+ // A program that jumps from a point where a local variable
+ // with automatic storage duration is not in scope to a point
+ // where it is in scope is ill-formed unless the variable has
+ // POD type and is declared without an initializer.
+
+ if (const Expr *init = VD->getInit()) {
+ // We actually give variables of record type (or array thereof)
+ // an initializer even if that initializer only calls a trivial
+ // ctor. Detect that case.
+ // FIXME: With generalized initializer lists, this may
+ // classify "X x{};" as having no initializer.
+ unsigned inDiagToUse = diag::note_protected_by_variable_init;
+
+ const CXXRecordDecl *record = 0;
+
+ if (const CXXConstructExpr *cce = dyn_cast<CXXConstructExpr>(init)) {
+ const CXXConstructorDecl *ctor = cce->getConstructor();
+ record = ctor->getParent();
+
+ if (ctor->isTrivial() && ctor->isDefaultConstructor()) {
+ if (Context.getLangOptions().CPlusPlus0x) {
+ inDiagToUse = (record->hasTrivialDestructor() ? 0 :
+ diag::note_protected_by_variable_nontriv_destructor);
+ } else {
+ if (record->isPOD())
+ inDiagToUse = 0;
+ }
}
-
- if (!CallsTrivialConstructor)
- InDiag = diag::note_protected_by_variable_init;
+ } else if (VD->getType()->isArrayType()) {
+ record = VD->getType()->getBaseElementTypeUnsafe()
+ ->getAsCXXRecordDecl();
}
-
- // Note whether we have a class with a non-trivial destructor.
- if (Record && !Record->hasTrivialDestructor())
+
+ if (inDiagToUse)
+ InDiag = inDiagToUse;
+
+ // Also object to indirect jumps which leave scopes with dtors.
+ if (record && !record->hasTrivialDestructor())
OutDiag = diag::note_exits_dtor;
}
}
- return std::make_pair(InDiag, OutDiag);
+ return ScopePair(InDiag, OutDiag);
}
if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
if (TD->getUnderlyingType()->isVariablyModifiedType())
- return std::make_pair((unsigned) diag::note_protected_by_vla_typedef, 0);
+ return ScopePair(diag::note_protected_by_vla_typedef, 0);
}
if (const TypeAliasDecl *TD = dyn_cast<TypeAliasDecl>(D)) {
if (TD->getUnderlyingType()->isVariablyModifiedType())
- return std::make_pair((unsigned) diag::note_protected_by_vla_type_alias, 0);
+ return ScopePair(diag::note_protected_by_vla_type_alias, 0);
}
- return std::make_pair(0U, 0U);
+ return ScopePair(0U, 0U);
}
/// \brief Build scope information for a declaration that is part of a DeclStmt.
void JumpScopeChecker::BuildScopeInformation(Decl *D, unsigned &ParentScope) {
- bool isCPlusPlus = this->S.getLangOptions().CPlusPlus;
-
// If this decl causes a new scope, push and switch to it.
- std::pair<unsigned,unsigned> Diags
- = GetDiagForGotoScopeDecl(D, isCPlusPlus);
+ std::pair<unsigned,unsigned> Diags = GetDiagForGotoScopeDecl(S.Context, D);
if (Diags.first || Diags.second) {
Scopes.push_back(GotoScope(ParentScope, Diags.first, Diags.second,
D->getLocation()));
@@ -205,11 +232,55 @@ void JumpScopeChecker::BuildScopeInformation(Decl *D, unsigned &ParentScope) {
BuildScopeInformation(Init, ParentScope);
}
+/// \brief Build scope information for a captured block literal variables.
+void JumpScopeChecker::BuildScopeInformation(VarDecl *D,
+ const BlockDecl *BDecl,
+ unsigned &ParentScope) {
+ // exclude captured __block variables; there's no destructor
+ // associated with the block literal for them.
+ if (D->hasAttr<BlocksAttr>())
+ return;
+ QualType T = D->getType();
+ QualType::DestructionKind destructKind = T.isDestructedType();
+ if (destructKind != QualType::DK_none) {
+ std::pair<unsigned,unsigned> Diags;
+ switch (destructKind) {
+ case QualType::DK_cxx_destructor:
+ Diags = ScopePair(diag::note_enters_block_captures_cxx_obj,
+ diag::note_exits_block_captures_cxx_obj);
+ break;
+ case QualType::DK_objc_strong_lifetime:
+ Diags = ScopePair(diag::note_enters_block_captures_strong,
+ diag::note_exits_block_captures_strong);
+ break;
+ case QualType::DK_objc_weak_lifetime:
+ Diags = ScopePair(diag::note_enters_block_captures_weak,
+ diag::note_exits_block_captures_weak);
+ break;
+ case QualType::DK_none:
+ llvm_unreachable("no-liftime captured variable");
+ }
+ SourceLocation Loc = D->getLocation();
+ if (Loc.isInvalid())
+ Loc = BDecl->getLocation();
+ Scopes.push_back(GotoScope(ParentScope,
+ Diags.first, Diags.second, Loc));
+ ParentScope = Scopes.size()-1;
+ }
+}
+
/// BuildScopeInformation - The statements from CI to CE are known to form a
/// coherent VLA scope with a specified parent node. Walk through the
/// statements, adding any labels or gotos to LabelAndGotoScopes and recursively
/// walking the AST as needed.
-void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
+void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned &origParentScope) {
+ // If this is a statement, rather than an expression, scopes within it don't
+ // propagate out into the enclosing scope. Otherwise we have to worry
+ // about block literals, which have the lifetime of their enclosing statement.
+ unsigned independentParentScope = origParentScope;
+ unsigned &ParentScope = ((isa<Expr>(S) && !isa<StmtExpr>(S))
+ ? origParentScope : independentParentScope);
+
bool SkipFirstSubStmt = false;
// If we found a label, remember that it is in ParentScope scope.
@@ -291,17 +362,17 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
BuildScopeInformation(*I, ParentScope);
continue;
}
-
// Disallow jumps into any part of an @try statement by pushing a scope and
// walking all sub-stmts in that scope.
if (ObjCAtTryStmt *AT = dyn_cast<ObjCAtTryStmt>(SubStmt)) {
+ unsigned newParentScope;
// Recursively walk the AST for the @try part.
Scopes.push_back(GotoScope(ParentScope,
diag::note_protected_by_objc_try,
diag::note_exits_objc_try,
AT->getAtTryLoc()));
if (Stmt *TryPart = AT->getTryBody())
- BuildScopeInformation(TryPart, Scopes.size()-1);
+ BuildScopeInformation(TryPart, (newParentScope = Scopes.size()-1));
// Jump from the catch to the finally or try is not valid.
for (unsigned I = 0, N = AT->getNumCatchStmts(); I != N; ++I) {
@@ -311,7 +382,8 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
diag::note_exits_objc_catch,
AC->getAtCatchLoc()));
// @catches are nested and it isn't
- BuildScopeInformation(AC->getCatchBody(), Scopes.size()-1);
+ BuildScopeInformation(AC->getCatchBody(),
+ (newParentScope = Scopes.size()-1));
}
// Jump from the finally to the try or catch is not valid.
@@ -320,12 +392,13 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
diag::note_protected_by_objc_finally,
diag::note_exits_objc_finally,
AF->getAtFinallyLoc()));
- BuildScopeInformation(AF, Scopes.size()-1);
+ BuildScopeInformation(AF, (newParentScope = Scopes.size()-1));
}
continue;
}
-
+
+ unsigned newParentScope;
// Disallow jumps into the protected statement of an @synchronized, but
// allow jumps into the object expression it protects.
if (ObjCAtSynchronizedStmt *AS = dyn_cast<ObjCAtSynchronizedStmt>(SubStmt)){
@@ -339,7 +412,8 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
diag::note_protected_by_objc_synchronized,
diag::note_exits_objc_synchronized,
AS->getAtSynchronizedLoc()));
- BuildScopeInformation(AS->getSynchBody(), Scopes.size()-1);
+ BuildScopeInformation(AS->getSynchBody(),
+ (newParentScope = Scopes.size()-1));
continue;
}
@@ -351,7 +425,7 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
diag::note_exits_cxx_try,
TS->getSourceRange().getBegin()));
if (Stmt *TryBlock = TS->getTryBlock())
- BuildScopeInformation(TryBlock, Scopes.size()-1);
+ BuildScopeInformation(TryBlock, (newParentScope = Scopes.size()-1));
// Jump from the catch into the try is not allowed either.
for (unsigned I = 0, E = TS->getNumHandlers(); I != E; ++I) {
@@ -360,12 +434,34 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
diag::note_protected_by_cxx_catch,
diag::note_exits_cxx_catch,
CS->getSourceRange().getBegin()));
- BuildScopeInformation(CS->getHandlerBlock(), Scopes.size()-1);
+ BuildScopeInformation(CS->getHandlerBlock(),
+ (newParentScope = Scopes.size()-1));
}
continue;
}
+ // Disallow jumps into the protected statement of an @autoreleasepool.
+ if (ObjCAutoreleasePoolStmt *AS = dyn_cast<ObjCAutoreleasePoolStmt>(SubStmt)){
+ // Recursively walk the AST for the @autoreleasepool part, protected by a new
+ // scope.
+ Scopes.push_back(GotoScope(ParentScope,
+ diag::note_protected_by_objc_autoreleasepool,
+ diag::note_exits_objc_autoreleasepool,
+ AS->getAtLoc()));
+ BuildScopeInformation(AS->getSubStmt(), (newParentScope = Scopes.size()-1));
+ continue;
+ }
+
+ if (const BlockExpr *BE = dyn_cast<BlockExpr>(SubStmt)) {
+ const BlockDecl *BDecl = BE->getBlockDecl();
+ for (BlockDecl::capture_const_iterator ci = BDecl->capture_begin(),
+ ce = BDecl->capture_end(); ci != ce; ++ci) {
+ VarDecl *variable = ci->getVariable();
+ BuildScopeInformation(variable, BDecl, ParentScope);
+ }
+ }
+
// Recursively walk the AST.
BuildScopeInformation(SubStmt, ParentScope);
}
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 8297b3155a8c..fdf3bb3cb012 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -141,9 +141,9 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
: TheTargetAttributesSema(0), FPFeatures(pp.getLangOptions()),
LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer),
Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
- ExternalSource(0), CodeCompleter(CodeCompleter), CurContext(0),
- PackContext(0), MSStructPragmaOn(false), VisContext(0),
- LateTemplateParser(0), OpaqueParser(0),
+ CollectStats(false), ExternalSource(0), CodeCompleter(CodeCompleter),
+ CurContext(0), PackContext(0), MSStructPragmaOn(false), VisContext(0),
+ ExprNeedsCleanups(0), LateTemplateParser(0), OpaqueParser(0),
IdResolver(pp.getLangOptions()), CXXTypeInfoDecl(0), MSVCGuidDecl(0),
GlobalNewDeleteDeclared(false),
CompleteTranslationUnit(CompleteTranslationUnit),
@@ -154,6 +154,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
AnalysisWarnings(*this)
{
TUScope = 0;
+ LoadedExternalKnownNamespaces = false;
+
if (getLangOptions().CPlusPlus)
FieldCollector.reset(new CXXFieldCollector());
@@ -162,7 +164,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
&Context);
ExprEvalContexts.push_back(
- ExpressionEvaluationContextRecord(PotentiallyEvaluated, 0));
+ ExpressionEvaluationContextRecord(PotentiallyEvaluated, 0, false));
FunctionScopes.push_back(new FunctionScopeInfo(Diags));
}
@@ -202,22 +204,61 @@ Sema::~Sema() {
ExternalSema->ForgetSema();
}
+
+/// makeUnavailableInSystemHeader - There is an error in the current
+/// context. If we're still in a system header, and we can plausibly
+/// make the relevant declaration unavailable instead of erroring, do
+/// so and return true.
+bool Sema::makeUnavailableInSystemHeader(SourceLocation loc,
+ llvm::StringRef msg) {
+ // If we're not in a function, it's an error.
+ FunctionDecl *fn = dyn_cast<FunctionDecl>(CurContext);
+ if (!fn) return false;
+
+ // If we're in template instantiation, it's an error.
+ if (!ActiveTemplateInstantiations.empty())
+ return false;
+
+ // If that function's not in a system header, it's an error.
+ if (!Context.getSourceManager().isInSystemHeader(loc))
+ return false;
+
+ // If the function is already unavailable, it's not an error.
+ if (fn->hasAttr<UnavailableAttr>()) return true;
+
+ fn->addAttr(new (Context) UnavailableAttr(loc, Context, msg));
+ return true;
+}
+
ASTMutationListener *Sema::getASTMutationListener() const {
return getASTConsumer().GetASTMutationListener();
}
+/// \brief Print out statistics about the semantic analysis.
+void Sema::PrintStats() const {
+ llvm::errs() << "\n*** Semantic Analysis Stats:\n";
+ llvm::errs() << NumSFINAEErrors << " SFINAE diagnostics trapped.\n";
+
+ BumpAlloc.PrintStats();
+ AnalysisWarnings.PrintStats();
+}
+
/// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast.
/// If there is already an implicit cast, merge into the existing one.
/// The result is of the given category.
ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty,
CastKind Kind, ExprValueKind VK,
- const CXXCastPath *BasePath) {
+ const CXXCastPath *BasePath,
+ CheckedConversionKind CCK) {
QualType ExprTy = Context.getCanonicalType(E->getType());
QualType TypeTy = Context.getCanonicalType(Ty);
if (ExprTy == TypeTy)
return Owned(E);
+ if (getLangOptions().ObjCAutoRefCount)
+ CheckObjCARCConversion(SourceRange(), Ty, E, CCK);
+
// If this is a derived-to-base cast to a through a virtual base, we
// need a vtable.
if (Kind == CK_DerivedToBase &&
@@ -729,8 +770,8 @@ void Sema::PopFunctionOrBlockScope(const AnalysisBasedWarnings::Policy *WP,
/// \brief Determine whether any errors occurred within this function/method/
/// block.
-bool Sema::hasAnyErrorsInThisFunction() const {
- return getCurFunction()->ErrorTrap.hasErrorOccurred();
+bool Sema::hasAnyUnrecoverableErrorsInThisFunction() const {
+ return getCurFunction()->ErrorTrap.hasUnrecoverableErrorOccurred();
}
BlockScopeInfo *Sema::getCurBlock() {
@@ -748,6 +789,10 @@ ExternalSemaSource::ReadMethodPool(Selector Sel) {
return std::pair<ObjCMethodList, ObjCMethodList>();
}
+void ExternalSemaSource::ReadKnownNamespaces(
+ llvm::SmallVectorImpl<NamespaceDecl *> &Namespaces) {
+}
+
void PrettyDeclStackTraceEntry::print(llvm::raw_ostream &OS) const {
SourceLocation Loc = this->Loc;
if (!Loc.isValid() && TheDecl) Loc = TheDecl->getLocation();
diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp
index e46ad5bcfeb5..d053d5a9e9fe 100644
--- a/lib/Sema/SemaCXXCast.cpp
+++ b/lib/Sema/SemaCXXCast.cpp
@@ -63,7 +63,8 @@ static void CheckDynamicCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
CastKind &Kind,
CXXCastPath &BasePath);
-static bool CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType);
+static bool CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType,
+ bool CheckCVR, bool CheckObjCLifetime);
// The Try functions attempt a specific way of casting. If they succeed, they
// return TC_Success. If their way of casting is not appropriate for the given
@@ -109,12 +110,14 @@ static TryCastResult TryStaticMemberPointerUpcast(Sema &Self, ExprResult &SrcExp
CXXCastPath &BasePath);
static TryCastResult TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr,
- QualType DestType, bool CStyle,
+ QualType DestType,
+ Sema::CheckedConversionKind CCK,
const SourceRange &OpRange,
unsigned &msg,
CastKind &Kind);
static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
- QualType DestType, bool CStyle,
+ QualType DestType,
+ Sema::CheckedConversionKind CCK,
const SourceRange &OpRange,
unsigned &msg,
CastKind &Kind,
@@ -131,17 +134,23 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
/// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's.
ExprResult
Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
- SourceLocation LAngleBracketLoc, ParsedType Ty,
+ SourceLocation LAngleBracketLoc, Declarator &D,
SourceLocation RAngleBracketLoc,
SourceLocation LParenLoc, Expr *E,
SourceLocation RParenLoc) {
-
- TypeSourceInfo *DestTInfo;
- QualType DestType = GetTypeFromParser(Ty, &DestTInfo);
- if (!DestTInfo)
- DestTInfo = Context.getTrivialTypeSourceInfo(DestType, SourceLocation());
- return BuildCXXNamedCast(OpLoc, Kind, DestTInfo, move(E),
+ assert(!D.isInvalidType());
+
+ TypeSourceInfo *TInfo = GetTypeForDeclaratorCast(D, E->getType());
+ if (D.isInvalidType())
+ return ExprError();
+
+ if (getLangOptions().CPlusPlus) {
+ // Check that there are no default arguments (C++ only).
+ CheckExtraCXXDefaultArguments(D);
+ }
+
+ return BuildCXXNamedCast(OpLoc, Kind, TInfo, move(E),
SourceRange(LAngleBracketLoc, RAngleBracketLoc),
SourceRange(LParenLoc, RParenLoc));
}
@@ -248,8 +257,10 @@ static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT,
InitializedEntity entity = InitializedEntity::InitializeTemporary(destType);
InitializationKind initKind
- = InitializationKind::CreateCast(/*type range?*/ range,
- (CT == CT_CStyle || CT == CT_Functional));
+ = (CT == CT_CStyle)? InitializationKind::CreateCStyleCast(range.getBegin(),
+ range)
+ : (CT == CT_Functional)? InitializationKind::CreateFunctionalCast(range)
+ : InitializationKind::CreateCast(/*type range?*/ range);
InitializationSequence sequence(S, entity, initKind, &src, 1);
assert(sequence.Failed() && "initialization succeeded on second try?");
@@ -373,8 +384,19 @@ static bool UnwrapDissimilarPointerTypes(QualType& T1, QualType& T2) {
/// DestType casts away constness as defined in C++ 5.2.11p8ff. This is used by
/// the cast checkers. Both arguments must denote pointer (possibly to member)
/// types.
+///
+/// \param CheckCVR Whether to check for const/volatile/restrict qualifiers.
+///
+/// \param CheckObjCLifetime Whether to check Objective-C lifetime qualifiers.
static bool
-CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType) {
+CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType,
+ bool CheckCVR, bool CheckObjCLifetime) {
+ // If the only checking we care about is for Objective-C lifetime qualifiers,
+ // and we're not in ARC mode, there's nothing to check.
+ if (!CheckCVR && CheckObjCLifetime &&
+ !Self.Context.getLangOptions().ObjCAutoRefCount)
+ return false;
+
// Casting away constness is defined in C++ 5.2.11p8 with reference to
// C++ 4.4. We piggyback on Sema::IsQualificationConversion for this, since
// the rules are non-trivial. So first we construct Tcv *...cv* as described
@@ -394,13 +416,23 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType) {
// purpose of this check, because other qualifiers (address spaces,
// Objective-C GC, etc.) are part of the type's identity.
while (UnwrapDissimilarPointerTypes(UnwrappedSrcType, UnwrappedDestType)) {
- Qualifiers SrcQuals;
+ // Determine the relevant qualifiers at this level.
+ Qualifiers SrcQuals, DestQuals;
Self.Context.getUnqualifiedArrayType(UnwrappedSrcType, SrcQuals);
- cv1.push_back(Qualifiers::fromCVRMask(SrcQuals.getCVRQualifiers()));
-
- Qualifiers DestQuals;
Self.Context.getUnqualifiedArrayType(UnwrappedDestType, DestQuals);
- cv2.push_back(Qualifiers::fromCVRMask(DestQuals.getCVRQualifiers()));
+
+ Qualifiers RetainedSrcQuals, RetainedDestQuals;
+ if (CheckCVR) {
+ RetainedSrcQuals.setCVRQualifiers(SrcQuals.getCVRQualifiers());
+ RetainedDestQuals.setCVRQualifiers(DestQuals.getCVRQualifiers());
+ }
+
+ if (CheckObjCLifetime &&
+ !DestQuals.compatiblyIncludesObjCLifetime(SrcQuals))
+ return true;
+
+ cv1.push_back(RetainedSrcQuals);
+ cv2.push_back(RetainedDestQuals);
}
if (cv1.empty())
return false;
@@ -420,8 +452,10 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType) {
}
// Test if they're compatible.
+ bool ObjCLifetimeConversion;
return SrcConstruct != DestConstruct &&
- !Self.IsQualificationConversion(SrcConstruct, DestConstruct, false);
+ !Self.IsQualificationConversion(SrcConstruct, DestConstruct, false,
+ ObjCLifetimeConversion);
}
/// CheckDynamicCast - Check that a dynamic_cast\<DestType\>(SrcExpr) is valid.
@@ -595,9 +629,10 @@ CheckReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
}
unsigned msg = diag::err_bad_cxx_cast_generic;
- if (TryReinterpretCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange,
- msg, Kind)
- != TC_Success && msg != 0)
+ TryCastResult tcr =
+ TryReinterpretCast(Self, SrcExpr, DestType,
+ /*CStyle*/false, OpRange, msg, Kind);
+ if (tcr != TC_Success && msg != 0)
{
if (SrcExpr.isInvalid()) // if conversion failed, don't report another error
return;
@@ -611,7 +646,12 @@ CheckReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
} else {
diagnoseBadCast(Self, msg, CT_Reinterpret, OpRange, SrcExpr.get(), DestType);
}
- }
+ } else if (tcr == TC_Success && Self.getLangOptions().ObjCAutoRefCount) {
+ Expr *Exp = SrcExpr.get();
+ // Note that Exp does not change with CCK_OtherCast cast type
+ Self.CheckObjCARCConversion(OpRange, DestType,
+ Exp, Sema::CCK_OtherCast);
+ }
}
@@ -654,8 +694,10 @@ CheckStaticCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
}
unsigned msg = diag::err_bad_cxx_cast_generic;
- if (TryStaticCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange, msg,
- Kind, BasePath) != TC_Success && msg != 0) {
+ TryCastResult tcr
+ = TryStaticCast(Self, SrcExpr, DestType, Sema::CCK_OtherCast, OpRange, msg,
+ Kind, BasePath);
+ if (tcr != TC_Success && msg != 0) {
if (SrcExpr.isInvalid())
return;
if (SrcExpr.get()->getType() == Self.Context.OverloadTy) {
@@ -667,6 +709,15 @@ CheckStaticCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
} else {
diagnoseBadCast(Self, msg, CT_Static, OpRange, SrcExpr.get(), DestType);
}
+ } else if (tcr == TC_Success) {
+ if (Kind == CK_BitCast)
+ Self.CheckCastAlign(SrcExpr.get(), DestType, OpRange);
+ if (Self.getLangOptions().ObjCAutoRefCount) {
+ Expr *Exp = SrcExpr.get();
+ // Note that Exp does not change with CCK_OtherCast cast type
+ Self.CheckObjCARCConversion(OpRange, DestType,
+ Exp, Sema::CCK_OtherCast);
+ }
}
else if (Kind == CK_BitCast)
Self.CheckCastAlign(SrcExpr.get(), DestType, OpRange);
@@ -676,10 +727,15 @@ CheckStaticCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
/// possible. If @p CStyle, ignore access restrictions on hierarchy casting
/// and casting away constness.
static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
- QualType DestType, bool CStyle,
+ QualType DestType,
+ Sema::CheckedConversionKind CCK,
const SourceRange &OpRange, unsigned &msg,
CastKind &Kind,
CXXCastPath &BasePath) {
+ // Determine whether we have the semantics of a C-style cast.
+ bool CStyle
+ = (CCK == Sema::CCK_CStyleCast || CCK == Sema::CCK_FunctionalCast);
+
// The order the tests is not entirely arbitrary. There is one conversion
// that can be handled in two different ways. Given:
// struct A {};
@@ -715,7 +771,7 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
// C++ 5.2.9p2: An expression e can be explicitly converted to a type T
// [...] if the declaration "T t(e);" is well-formed, [...].
- tcr = TryStaticImplicitCast(Self, SrcExpr, DestType, CStyle, OpRange, msg,
+ tcr = TryStaticImplicitCast(Self, SrcExpr, DestType, CCK, OpRange, msg,
Kind);
if (SrcExpr.isInvalid())
return TC_Failed;
@@ -792,10 +848,20 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
QualType DestPointee = DestPointer->getPointeeType();
if (DestPointee->isIncompleteOrObjectType()) {
// This is definitely the intended conversion, but it might fail due
- // to a const violation.
- if (!CStyle && !DestPointee.isAtLeastAsQualifiedAs(SrcPointee)) {
- msg = diag::err_bad_cxx_cast_qualifiers_away;
- return TC_Failed;
+ // to a qualifier violation. Note that we permit Objective-C lifetime
+ // and GC qualifier mismatches here.
+ if (!CStyle) {
+ Qualifiers DestPointeeQuals = DestPointee.getQualifiers();
+ Qualifiers SrcPointeeQuals = SrcPointee.getQualifiers();
+ DestPointeeQuals.removeObjCGCAttr();
+ DestPointeeQuals.removeObjCLifetime();
+ SrcPointeeQuals.removeObjCGCAttr();
+ SrcPointeeQuals.removeObjCLifetime();
+ if (DestPointeeQuals != SrcPointeeQuals &&
+ !DestPointeeQuals.compatiblyIncludes(SrcPointeeQuals)) {
+ msg = diag::err_bad_cxx_cast_qualifiers_away;
+ return TC_Failed;
+ }
}
Kind = CK_BitCast;
return TC_Success;
@@ -845,6 +911,7 @@ TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType,
// FIXME: Should allow casting away constness if CStyle.
bool DerivedToBase;
bool ObjCConversion;
+ bool ObjCLifetimeConversion;
QualType FromType = SrcExpr->getType();
QualType ToType = R->getPointeeType();
if (CStyle) {
@@ -854,8 +921,9 @@ TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType,
if (Self.CompareReferenceRelationship(SrcExpr->getLocStart(),
ToType, FromType,
- DerivedToBase, ObjCConversion) <
- Sema::Ref_Compatible_With_Added_Qualification) {
+ DerivedToBase, ObjCConversion,
+ ObjCLifetimeConversion)
+ < Sema::Ref_Compatible_With_Added_Qualification) {
msg = diag::err_bad_lvalue_to_rvalue_cast;
return TC_Failed;
}
@@ -1172,7 +1240,8 @@ TryStaticMemberPointerUpcast(Sema &Self, ExprResult &SrcExpr, QualType SrcType,
/// @c static_cast if the declaration "T t(e);" is well-formed [...].
TryCastResult
TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
- bool CStyle, const SourceRange &OpRange, unsigned &msg,
+ Sema::CheckedConversionKind CCK,
+ const SourceRange &OpRange, unsigned &msg,
CastKind &Kind) {
if (DestType->isRecordType()) {
if (Self.RequireCompleteType(OpRange.getBegin(), DestType,
@@ -1184,7 +1253,11 @@ TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
InitializedEntity Entity = InitializedEntity::InitializeTemporary(DestType);
InitializationKind InitKind
- = InitializationKind::CreateCast(/*FIXME:*/OpRange, CStyle);
+ = (CCK == Sema::CCK_CStyleCast)
+ ? InitializationKind::CreateCStyleCast(OpRange.getBegin(), OpRange)
+ : (CCK == Sema::CCK_FunctionalCast)
+ ? InitializationKind::CreateFunctionalCast(OpRange)
+ : InitializationKind::CreateCast(OpRange);
Expr *SrcExprRaw = SrcExpr.get();
InitializationSequence InitSeq(Self, Entity, InitKind, &SrcExprRaw, 1);
@@ -1193,7 +1266,8 @@ TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
// There is no other way that works.
// On the other hand, if we're checking a C-style cast, we've still got
// the reinterpret_cast way.
-
+ bool CStyle
+ = (CCK == Sema::CCK_CStyleCast || CCK == Sema::CCK_FunctionalCast);
if (InitSeq.Failed() && (CStyle || !DestType->isReferenceType()))
return TC_NotApplicable;
@@ -1428,7 +1502,8 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
// constness.
// A reinterpret_cast followed by a const_cast can, though, so in C-style,
// we accept it.
- if (!CStyle && CastsAwayConstness(Self, SrcType, DestType)) {
+ if (CastsAwayConstness(Self, SrcType, DestType, /*CheckCVR=*/!CStyle,
+ /*CheckObjCLifetime=*/CStyle)) {
msg = diag::err_bad_cxx_cast_qualifiers_away;
return TC_Failed;
}
@@ -1543,7 +1618,8 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
// C++ 5.2.10p2: The reinterpret_cast operator shall not cast away constness.
// The C-style cast operator can.
- if (!CStyle && CastsAwayConstness(Self, SrcType, DestType)) {
+ if (CastsAwayConstness(Self, SrcType, DestType, /*CheckCVR=*/!CStyle,
+ /*CheckObjCLifetime=*/CStyle)) {
msg = diag::err_bad_cxx_cast_qualifiers_away;
return TC_Failed;
}
@@ -1675,11 +1751,14 @@ Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK,
if (tcr == TC_Success)
Kind = CK_NoOp;
+ Sema::CheckedConversionKind CCK
+ = FunctionalStyle? Sema::CCK_FunctionalCast
+ : Sema::CCK_CStyleCast;
if (tcr == TC_NotApplicable) {
// ... or if that is not possible, a static_cast, ignoring const, ...
ExprResult CastExprRes = Owned(CastExpr);
- tcr = TryStaticCast(*this, CastExprRes, CastTy, /*CStyle*/true, R, msg,
- Kind, BasePath);
+ tcr = TryStaticCast(*this, CastExprRes, CastTy, CCK, R, msg, Kind,
+ BasePath);
if (CastExprRes.isInvalid())
return ExprError();
CastExpr = CastExprRes.take();
@@ -1694,6 +1773,9 @@ Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK,
}
}
+ if (getLangOptions().ObjCAutoRefCount && tcr == TC_Success)
+ CheckObjCARCConversion(R, CastTy, CastExpr, CCK);
+
if (tcr != TC_Success && msg != 0) {
if (CastExpr->getType() == Context.OverloadTy) {
DeclAccessPair Found;
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 61d9e93f2ff5..5f8c9c62a409 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -211,25 +211,40 @@ bool Sema::RequireCompleteDeclContext(CXXScopeSpec &SS,
DeclContext *DC) {
assert(DC != 0 && "given null context");
- if (TagDecl *Tag = dyn_cast<TagDecl>(DC)) {
+ if (TagDecl *tag = dyn_cast<TagDecl>(DC)) {
// If this is a dependent type, then we consider it complete.
- if (Tag->isDependentContext())
+ if (tag->isDependentContext())
return false;
// If we're currently defining this type, then lookup into the
// type is okay: don't complain that it isn't complete yet.
- const TagType *TagT = Context.getTypeDeclType(Tag)->getAs<TagType>();
- if (TagT && TagT->isBeingDefined())
+ QualType type = Context.getTypeDeclType(tag);
+ const TagType *tagType = type->getAs<TagType>();
+ if (tagType && tagType->isBeingDefined())
return false;
+ SourceLocation loc = SS.getLastQualifierNameLoc();
+ if (loc.isInvalid()) loc = SS.getRange().getBegin();
+
// The type must be complete.
- if (RequireCompleteType(SS.getRange().getBegin(),
- Context.getTypeDeclType(Tag),
+ if (RequireCompleteType(loc, type,
PDiag(diag::err_incomplete_nested_name_spec)
<< SS.getRange())) {
SS.SetInvalid(SS.getRange());
return true;
}
+
+ // Fixed enum types are complete, but they aren't valid as scopes
+ // until we see a definition, so awkwardly pull out this special
+ // case.
+ if (const EnumType *enumType = dyn_cast_or_null<EnumType>(tagType)) {
+ if (!enumType->getDecl()->isDefinition()) {
+ Diag(loc, diag::err_incomplete_nested_name_spec)
+ << type << SS.getRange();
+ SS.SetInvalid(SS.getRange());
+ return true;
+ }
+ }
}
return false;
@@ -464,26 +479,29 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
// We haven't found anything, and we're not recovering from a
// different kind of error, so look for typos.
DeclarationName Name = Found.getLookupName();
- if (CorrectTypo(Found, S, &SS, LookupCtx, EnteringContext,
- CTC_NoKeywords) &&
- Found.isSingleResult() &&
- isAcceptableNestedNameSpecifier(Found.getAsSingle<NamedDecl>())) {
+ TypoCorrection Corrected;
+ Found.clear();
+ if ((Corrected = CorrectTypo(Found.getLookupNameInfo(),
+ Found.getLookupKind(), S, &SS, LookupCtx,
+ EnteringContext, CTC_NoKeywords)) &&
+ isAcceptableNestedNameSpecifier(Corrected.getCorrectionDecl())) {
+ std::string CorrectedStr(Corrected.getAsString(getLangOptions()));
+ std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOptions()));
if (LookupCtx)
Diag(Found.getNameLoc(), diag::err_no_member_suggest)
- << Name << LookupCtx << Found.getLookupName() << SS.getRange()
- << FixItHint::CreateReplacement(Found.getNameLoc(),
- Found.getLookupName().getAsString());
+ << Name << LookupCtx << CorrectedQuotedStr << SS.getRange()
+ << FixItHint::CreateReplacement(Found.getNameLoc(), CorrectedStr);
else
Diag(Found.getNameLoc(), diag::err_undeclared_var_use_suggest)
- << Name << Found.getLookupName()
- << FixItHint::CreateReplacement(Found.getNameLoc(),
- Found.getLookupName().getAsString());
+ << Name << CorrectedQuotedStr
+ << FixItHint::CreateReplacement(Found.getNameLoc(), CorrectedStr);
- if (NamedDecl *ND = Found.getAsSingle<NamedDecl>())
- Diag(ND->getLocation(), diag::note_previous_decl)
- << ND->getDeclName();
+ if (NamedDecl *ND = Corrected.getCorrectionDecl()) {
+ Diag(ND->getLocation(), diag::note_previous_decl) << CorrectedQuotedStr;
+ Found.addDecl(ND);
+ }
+ Found.setLookupName(Corrected.getCorrection());
} else {
- Found.clear();
Found.setLookupName(&Identifier);
}
}
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 05c257ab8332..690a29d281d2 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -22,6 +22,7 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
@@ -319,12 +320,41 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) {
}
// Memset/memcpy/memmove handling
- if (FDecl->getLinkage() == ExternalLinkage &&
- (!getLangOptions().CPlusPlus || FDecl->isExternC())) {
- if (FnInfo->isStr("memset") || FnInfo->isStr("memcpy") ||
- FnInfo->isStr("memmove"))
- CheckMemsetcpymoveArguments(TheCall, FnInfo);
+ int CMF = -1;
+ switch (FDecl->getBuiltinID()) {
+ case Builtin::BI__builtin_memset:
+ case Builtin::BI__builtin___memset_chk:
+ case Builtin::BImemset:
+ CMF = CMF_Memset;
+ break;
+
+ case Builtin::BI__builtin_memcpy:
+ case Builtin::BI__builtin___memcpy_chk:
+ case Builtin::BImemcpy:
+ CMF = CMF_Memcpy;
+ break;
+
+ case Builtin::BI__builtin_memmove:
+ case Builtin::BI__builtin___memmove_chk:
+ case Builtin::BImemmove:
+ CMF = CMF_Memmove;
+ break;
+
+ default:
+ if (FDecl->getLinkage() == ExternalLinkage &&
+ (!getLangOptions().CPlusPlus || FDecl->isExternC())) {
+ if (FnInfo->isStr("memset"))
+ CMF = CMF_Memset;
+ else if (FnInfo->isStr("memcpy"))
+ CMF = CMF_Memcpy;
+ else if (FnInfo->isStr("memmove"))
+ CMF = CMF_Memmove;
+ }
+ break;
}
+
+ if (CMF != -1)
+ CheckMemsetcpymoveArguments(TheCall, CheckedMemoryFunction(CMF), FnInfo);
return false;
}
@@ -382,14 +412,14 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
// casts here.
// FIXME: We don't allow floating point scalars as input.
Expr *FirstArg = TheCall->getArg(0);
- if (!FirstArg->getType()->isPointerType()) {
+ const PointerType *pointerType = FirstArg->getType()->getAs<PointerType>();
+ if (!pointerType) {
Diag(DRE->getLocStart(), diag::err_atomic_builtin_must_be_pointer)
<< FirstArg->getType() << FirstArg->getSourceRange();
return ExprError();
}
- QualType ValType =
- FirstArg->getType()->getAs<PointerType>()->getPointeeType();
+ QualType ValType = pointerType->getPointeeType();
if (!ValType->isIntegerType() && !ValType->isAnyPointerType() &&
!ValType->isBlockPointerType()) {
Diag(DRE->getLocStart(), diag::err_atomic_builtin_must_be_pointer_intptr)
@@ -397,6 +427,20 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
return ExprError();
}
+ switch (ValType.getObjCLifetime()) {
+ case Qualifiers::OCL_None:
+ case Qualifiers::OCL_ExplicitNone:
+ // okay
+ break;
+
+ case Qualifiers::OCL_Weak:
+ case Qualifiers::OCL_Strong:
+ case Qualifiers::OCL_Autoreleasing:
+ Diag(DRE->getLocStart(), diag::err_arc_atomic_ownership)
+ << ValType << FirstArg->getSourceRange();
+ return ExprError();
+ }
+
// The majority of builtins return a value, but a few have special return
// types, so allow them to override appropriately below.
QualType ResultType = ValType;
@@ -518,7 +562,8 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
CastKind Kind = CK_Invalid;
ExprValueKind VK = VK_RValue;
CXXCastPath BasePath;
- Arg = CheckCastTypes(Arg.get()->getSourceRange(), ValType, Arg.take(), Kind, VK, BasePath);
+ Arg = CheckCastTypes(Arg.get()->getLocStart(), Arg.get()->getSourceRange(),
+ ValType, Arg.take(), Kind, VK, BasePath);
if (Arg.isInvalid())
return ExprError();
@@ -1812,6 +1857,27 @@ static bool isDynamicClassType(QualType T) {
return false;
}
+/// \brief If E is a sizeof expression, returns its argument expression,
+/// otherwise returns NULL.
+static const Expr *getSizeOfExprArg(const Expr* E) {
+ if (const UnaryExprOrTypeTraitExpr *SizeOf =
+ dyn_cast<UnaryExprOrTypeTraitExpr>(E))
+ if (SizeOf->getKind() == clang::UETT_SizeOf && !SizeOf->isArgumentType())
+ return SizeOf->getArgumentExpr()->IgnoreParenImpCasts();
+
+ return 0;
+}
+
+/// \brief If E is a sizeof expression, returns its argument type.
+static QualType getSizeOfArgType(const Expr* E) {
+ if (const UnaryExprOrTypeTraitExpr *SizeOf =
+ dyn_cast<UnaryExprOrTypeTraitExpr>(E))
+ if (SizeOf->getKind() == clang::UETT_SizeOf)
+ return SizeOf->getTypeOfArgument();
+
+ return QualType();
+}
+
/// \brief Check for dangerous or invalid arguments to memset().
///
/// This issues warnings on known problematic, dangerous or unspecified
@@ -1819,35 +1885,95 @@ static bool isDynamicClassType(QualType T) {
///
/// \param Call The call expression to diagnose.
void Sema::CheckMemsetcpymoveArguments(const CallExpr *Call,
- const IdentifierInfo *FnName) {
+ CheckedMemoryFunction CMF,
+ IdentifierInfo *FnName) {
// It is possible to have a non-standard definition of memset. Validate
- // we have the proper number of arguments, and if not, abort further
- // checking.
- if (Call->getNumArgs() != 3)
+ // we have enough arguments, and if not, abort further checking.
+ if (Call->getNumArgs() < 3)
return;
- unsigned LastArg = FnName->isStr("memset")? 1 : 2;
+ unsigned LastArg = (CMF == CMF_Memset? 1 : 2);
+ const Expr *LenExpr = Call->getArg(2)->IgnoreParenImpCasts();
+
+ // We have special checking when the length is a sizeof expression.
+ QualType SizeOfArgTy = getSizeOfArgType(LenExpr);
+ const Expr *SizeOfArg = getSizeOfExprArg(LenExpr);
+ llvm::FoldingSetNodeID SizeOfArgID;
+
for (unsigned ArgIdx = 0; ArgIdx != LastArg; ++ArgIdx) {
const Expr *Dest = Call->getArg(ArgIdx)->IgnoreParenImpCasts();
+ SourceRange ArgRange = Call->getArg(ArgIdx)->getSourceRange();
QualType DestTy = Dest->getType();
if (const PointerType *DestPtrTy = DestTy->getAs<PointerType>()) {
QualType PointeeTy = DestPtrTy->getPointeeType();
+
+ // Never warn about void type pointers. This can be used to suppress
+ // false positives.
if (PointeeTy->isVoidType())
continue;
+ // Catch "memset(p, 0, sizeof(p))" -- needs to be sizeof(*p). Do this by
+ // actually comparing the expressions for equality. Because computing the
+ // expression IDs can be expensive, we only do this if the diagnostic is
+ // enabled.
+ if (SizeOfArg &&
+ Diags.getDiagnosticLevel(diag::warn_sizeof_pointer_expr_memaccess,
+ SizeOfArg->getExprLoc())) {
+ // We only compute IDs for expressions if the warning is enabled, and
+ // cache the sizeof arg's ID.
+ if (SizeOfArgID == llvm::FoldingSetNodeID())
+ SizeOfArg->Profile(SizeOfArgID, Context, true);
+ llvm::FoldingSetNodeID DestID;
+ Dest->Profile(DestID, Context, true);
+ if (DestID == SizeOfArgID) {
+ unsigned ActionIdx = 0; // Default is to suggest dereferencing.
+ if (const UnaryOperator *UnaryOp = dyn_cast<UnaryOperator>(Dest))
+ if (UnaryOp->getOpcode() == UO_AddrOf)
+ ActionIdx = 1; // If its an address-of operator, just remove it.
+ if (Context.getTypeSize(PointeeTy) == Context.getCharWidth())
+ ActionIdx = 2; // If the pointee's size is sizeof(char),
+ // suggest an explicit length.
+ DiagRuntimeBehavior(SizeOfArg->getExprLoc(), Dest,
+ PDiag(diag::warn_sizeof_pointer_expr_memaccess)
+ << FnName << ArgIdx << ActionIdx
+ << Dest->getSourceRange()
+ << SizeOfArg->getSourceRange());
+ break;
+ }
+ }
+
+ // Also check for cases where the sizeof argument is the exact same
+ // type as the memory argument, and where it points to a user-defined
+ // record type.
+ if (SizeOfArgTy != QualType()) {
+ if (PointeeTy->isRecordType() &&
+ Context.typesAreCompatible(SizeOfArgTy, DestTy)) {
+ DiagRuntimeBehavior(LenExpr->getExprLoc(), Dest,
+ PDiag(diag::warn_sizeof_pointer_type_memaccess)
+ << FnName << SizeOfArgTy << ArgIdx
+ << PointeeTy << Dest->getSourceRange()
+ << LenExpr->getSourceRange());
+ break;
+ }
+ }
+
+ unsigned DiagID;
+
// Always complain about dynamic classes.
- if (isDynamicClassType(PointeeTy)) {
- DiagRuntimeBehavior(
- Dest->getExprLoc(), Dest,
- PDiag(diag::warn_dyn_class_memaccess)
- << ArgIdx << FnName << PointeeTy
- << Call->getCallee()->getSourceRange());
- } else {
+ if (isDynamicClassType(PointeeTy))
+ DiagID = diag::warn_dyn_class_memaccess;
+ else if (PointeeTy.hasNonTrivialObjCLifetime() && CMF != CMF_Memset)
+ DiagID = diag::warn_arc_object_memaccess;
+ else
continue;
- }
- SourceRange ArgRange = Call->getArg(0)->getSourceRange();
+ DiagRuntimeBehavior(
+ Dest->getExprLoc(), Dest,
+ PDiag(DiagID)
+ << ArgIdx << FnName << PointeeTy
+ << Call->getCallee()->getSourceRange());
+
DiagRuntimeBehavior(
Dest->getExprLoc(), Dest,
PDiag(diag::note_bad_memaccess_silence)
@@ -1873,7 +1999,8 @@ Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
// Perform checking for returned stack addresses, local blocks,
// label addresses or references to temporaries.
- if (lhsType->isPointerType() || lhsType->isBlockPointerType()) {
+ if (lhsType->isPointerType() ||
+ (!getLangOptions().ObjCAutoRefCount && lhsType->isBlockPointerType())) {
stackE = EvalAddr(RetValExp, refVars);
} else if (lhsType->isReferenceType()) {
stackE = EvalVal(RetValExp, refVars);
@@ -2044,7 +2171,8 @@ static Expr *EvalAddr(Expr *E, llvm::SmallVectorImpl<DeclRefExpr *> &refVars) {
// pointer values, and pointer-to-pointer conversions.
case Stmt::ImplicitCastExprClass:
case Stmt::CStyleCastExprClass:
- case Stmt::CXXFunctionalCastExprClass: {
+ case Stmt::CXXFunctionalCastExprClass:
+ case Stmt::ObjCBridgedCastExprClass: {
Expr* SubExpr = cast<CastExpr>(E)->getSubExpr();
QualType T = SubExpr->getType();
@@ -2077,6 +2205,14 @@ static Expr *EvalAddr(Expr *E, llvm::SmallVectorImpl<DeclRefExpr *> &refVars) {
return NULL;
}
+ case Stmt::MaterializeTemporaryExprClass:
+ if (Expr *Result = EvalAddr(
+ cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr(),
+ refVars))
+ return Result;
+
+ return E;
+
// Everything else: we simply don't reason about them.
default:
return NULL;
@@ -2178,6 +2314,14 @@ do {
return EvalVal(M->getBase(), refVars);
}
+ case Stmt::MaterializeTemporaryExprClass:
+ if (Expr *Result = EvalVal(
+ cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr(),
+ refVars))
+ return Result;
+
+ return E;
+
default:
// Check that we don't return or take the address of a reference to a
// temporary. This is only useful in C++.
@@ -2442,15 +2586,24 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
case BO_NE:
return IntRange::forBoolType();
- // The type of these compound assignments is the type of the LHS,
- // so the RHS is not necessarily an integer.
+ // The type of the assignments is the type of the LHS, so the RHS
+ // is not necessarily the same type.
case BO_MulAssign:
case BO_DivAssign:
case BO_RemAssign:
case BO_AddAssign:
case BO_SubAssign:
+ case BO_XorAssign:
+ case BO_OrAssign:
+ // TODO: bitfields?
return IntRange::forValueOfType(C, E->getType());
+ // Simple assignments just pass through the RHS, which will have
+ // been coerced to the LHS type.
+ case BO_Assign:
+ // TODO: bitfields?
+ return GetExprRange(C, BO->getRHS(), MaxWidth);
+
// Operations with opaque sources are black-listed.
case BO_PtrMemD:
case BO_PtrMemI:
@@ -2506,14 +2659,54 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
case BO_Sub:
if (BO->getLHS()->getType()->isPointerType())
return IntRange::forValueOfType(C, E->getType());
- // fallthrough
+ break;
- default:
+ // The width of a division result is mostly determined by the size
+ // of the LHS.
+ case BO_Div: {
+ // Don't 'pre-truncate' the operands.
+ unsigned opWidth = C.getIntWidth(E->getType());
+ IntRange L = GetExprRange(C, BO->getLHS(), opWidth);
+
+ // If the divisor is constant, use that.
+ llvm::APSInt divisor;
+ if (BO->getRHS()->isIntegerConstantExpr(divisor, C)) {
+ unsigned log2 = divisor.logBase2(); // floor(log_2(divisor))
+ if (log2 >= L.Width)
+ L.Width = (L.NonNegative ? 0 : 1);
+ else
+ L.Width = std::min(L.Width - log2, MaxWidth);
+ return L;
+ }
+
+ // Otherwise, just use the LHS's width.
+ IntRange R = GetExprRange(C, BO->getRHS(), opWidth);
+ return IntRange(L.Width, L.NonNegative && R.NonNegative);
+ }
+
+ // The result of a remainder can't be larger than the result of
+ // either side.
+ case BO_Rem: {
+ // Don't 'pre-truncate' the operands.
+ unsigned opWidth = C.getIntWidth(E->getType());
+ IntRange L = GetExprRange(C, BO->getLHS(), opWidth);
+ IntRange R = GetExprRange(C, BO->getRHS(), opWidth);
+
+ IntRange meet = IntRange::meet(L, R);
+ meet.Width = std::min(meet.Width, MaxWidth);
+ return meet;
+ }
+
+ // The default behavior is okay for these.
+ case BO_Mul:
+ case BO_Add:
+ case BO_Xor:
+ case BO_Or:
break;
}
- // Treat every other operator as if it were closed on the
- // narrowest type that encompasses both operands.
+ // The default case is to treat the operation as if it were closed
+ // on the narrowest type that encompasses both operands.
IntRange L = GetExprRange(C, BO->getLHS(), MaxWidth);
IntRange R = GetExprRange(C, BO->getRHS(), MaxWidth);
return IntRange::join(L, R);
@@ -2837,18 +3030,16 @@ void DiagnoseFloatingLiteralImpCast(Sema &S, FloatingLiteral *FL, QualType T,
if (&Value.getSemantics() == &llvm::APFloat::PPCDoubleDouble)
return;
- // Try to convert this exactly to an 64-bit integer. FIXME: It would be
- // nice to support arbitrarily large integers here.
+ // Try to convert this exactly to an integer.
bool isExact = false;
- uint64_t IntegerPart;
- if (Value.convertToInteger(&IntegerPart, 64, /*isSigned=*/true,
+ llvm::APSInt IntegerValue(S.Context.getIntWidth(T),
+ T->hasUnsignedIntegerRepresentation());
+ if (Value.convertToInteger(IntegerValue,
llvm::APFloat::rmTowardZero, &isExact)
!= llvm::APFloat::opOK || !isExact)
return;
- llvm::APInt IntegerValue(64, IntegerPart, /*isSigned=*/true);
-
- std::string LiteralValue = IntegerValue.toString(10, /*isSigned=*/true);
+ std::string LiteralValue = IntegerValue.toString(10);
S.Diag(FL->getExprLoc(), diag::note_fix_integral_float_as_integer)
<< FixItHint::CreateReplacement(FL->getSourceRange(), LiteralValue);
}
@@ -2895,6 +3086,11 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
return;
return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_vector_scalar);
}
+
+ // If the vector cast is cast between two vectors of the same size, it is
+ // a bitcast, not a conversion.
+ if (S.Context.getTypeSize(Source) == S.Context.getTypeSize(Target))
+ return;
Source = cast<VectorType>(Source)->getElementType().getTypePtr();
Target = cast<VectorType>(Target)->getElementType().getTypePtr();
@@ -2989,9 +3185,7 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
return;
}
- // People want to build with -Wshorten-64-to-32 and not -Wconversion
- // and by god we'll let them.
-
+ // People want to build with -Wshorten-64-to-32 and not -Wconversion.
if (isFromSystemMacro(S, CC))
return;
@@ -3356,3 +3550,268 @@ void Sema::CheckArrayAccess(const Expr *expr) {
}
}
}
+
+//===--- CHECK: Objective-C retain cycles ----------------------------------//
+
+namespace {
+ struct RetainCycleOwner {
+ RetainCycleOwner() : Variable(0), Indirect(false) {}
+ VarDecl *Variable;
+ SourceRange Range;
+ SourceLocation Loc;
+ bool Indirect;
+
+ void setLocsFrom(Expr *e) {
+ Loc = e->getExprLoc();
+ Range = e->getSourceRange();
+ }
+ };
+}
+
+/// Consider whether capturing the given variable can possibly lead to
+/// a retain cycle.
+static bool considerVariable(VarDecl *var, Expr *ref, RetainCycleOwner &owner) {
+ // In ARC, it's captured strongly iff the variable has __strong
+ // lifetime. In MRR, it's captured strongly if the variable is
+ // __block and has an appropriate type.
+ if (var->getType().getObjCLifetime() != Qualifiers::OCL_Strong)
+ return false;
+
+ owner.Variable = var;
+ owner.setLocsFrom(ref);
+ return true;
+}
+
+static bool findRetainCycleOwner(Expr *e, RetainCycleOwner &owner) {
+ while (true) {
+ e = e->IgnoreParens();
+ if (CastExpr *cast = dyn_cast<CastExpr>(e)) {
+ switch (cast->getCastKind()) {
+ case CK_BitCast:
+ case CK_LValueBitCast:
+ case CK_LValueToRValue:
+ case CK_ObjCReclaimReturnedObject:
+ e = cast->getSubExpr();
+ continue;
+
+ case CK_GetObjCProperty: {
+ // Bail out if this isn't a strong explicit property.
+ const ObjCPropertyRefExpr *pre = cast->getSubExpr()->getObjCProperty();
+ if (pre->isImplicitProperty()) return false;
+ ObjCPropertyDecl *property = pre->getExplicitProperty();
+ if (!(property->getPropertyAttributes() &
+ (ObjCPropertyDecl::OBJC_PR_retain |
+ ObjCPropertyDecl::OBJC_PR_copy |
+ ObjCPropertyDecl::OBJC_PR_strong)) &&
+ !(property->getPropertyIvarDecl() &&
+ property->getPropertyIvarDecl()->getType()
+ .getObjCLifetime() == Qualifiers::OCL_Strong))
+ return false;
+
+ owner.Indirect = true;
+ e = const_cast<Expr*>(pre->getBase());
+ continue;
+ }
+
+ default:
+ return false;
+ }
+ }
+
+ if (ObjCIvarRefExpr *ref = dyn_cast<ObjCIvarRefExpr>(e)) {
+ ObjCIvarDecl *ivar = ref->getDecl();
+ if (ivar->getType().getObjCLifetime() != Qualifiers::OCL_Strong)
+ return false;
+
+ // Try to find a retain cycle in the base.
+ if (!findRetainCycleOwner(ref->getBase(), owner))
+ return false;
+
+ if (ref->isFreeIvar()) owner.setLocsFrom(ref);
+ owner.Indirect = true;
+ return true;
+ }
+
+ if (DeclRefExpr *ref = dyn_cast<DeclRefExpr>(e)) {
+ VarDecl *var = dyn_cast<VarDecl>(ref->getDecl());
+ if (!var) return false;
+ return considerVariable(var, ref, owner);
+ }
+
+ if (BlockDeclRefExpr *ref = dyn_cast<BlockDeclRefExpr>(e)) {
+ owner.Variable = ref->getDecl();
+ owner.setLocsFrom(ref);
+ return true;
+ }
+
+ if (MemberExpr *member = dyn_cast<MemberExpr>(e)) {
+ if (member->isArrow()) return false;
+
+ // Don't count this as an indirect ownership.
+ e = member->getBase();
+ continue;
+ }
+
+ // Array ivars?
+
+ return false;
+ }
+}
+
+namespace {
+ struct FindCaptureVisitor : EvaluatedExprVisitor<FindCaptureVisitor> {
+ FindCaptureVisitor(ASTContext &Context, VarDecl *variable)
+ : EvaluatedExprVisitor<FindCaptureVisitor>(Context),
+ Variable(variable), Capturer(0) {}
+
+ VarDecl *Variable;
+ Expr *Capturer;
+
+ void VisitDeclRefExpr(DeclRefExpr *ref) {
+ if (ref->getDecl() == Variable && !Capturer)
+ Capturer = ref;
+ }
+
+ void VisitBlockDeclRefExpr(BlockDeclRefExpr *ref) {
+ if (ref->getDecl() == Variable && !Capturer)
+ Capturer = ref;
+ }
+
+ void VisitObjCIvarRefExpr(ObjCIvarRefExpr *ref) {
+ if (Capturer) return;
+ Visit(ref->getBase());
+ if (Capturer && ref->isFreeIvar())
+ Capturer = ref;
+ }
+
+ void VisitBlockExpr(BlockExpr *block) {
+ // Look inside nested blocks
+ if (block->getBlockDecl()->capturesVariable(Variable))
+ Visit(block->getBlockDecl()->getBody());
+ }
+ };
+}
+
+/// Check whether the given argument is a block which captures a
+/// variable.
+static Expr *findCapturingExpr(Sema &S, Expr *e, RetainCycleOwner &owner) {
+ assert(owner.Variable && owner.Loc.isValid());
+
+ e = e->IgnoreParenCasts();
+ BlockExpr *block = dyn_cast<BlockExpr>(e);
+ if (!block || !block->getBlockDecl()->capturesVariable(owner.Variable))
+ return 0;
+
+ FindCaptureVisitor visitor(S.Context, owner.Variable);
+ visitor.Visit(block->getBlockDecl()->getBody());
+ return visitor.Capturer;
+}
+
+static void diagnoseRetainCycle(Sema &S, Expr *capturer,
+ RetainCycleOwner &owner) {
+ assert(capturer);
+ assert(owner.Variable && owner.Loc.isValid());
+
+ S.Diag(capturer->getExprLoc(), diag::warn_arc_retain_cycle)
+ << owner.Variable << capturer->getSourceRange();
+ S.Diag(owner.Loc, diag::note_arc_retain_cycle_owner)
+ << owner.Indirect << owner.Range;
+}
+
+/// Check for a keyword selector that starts with the word 'add' or
+/// 'set'.
+static bool isSetterLikeSelector(Selector sel) {
+ if (sel.isUnarySelector()) return false;
+
+ llvm::StringRef str = sel.getNameForSlot(0);
+ while (!str.empty() && str.front() == '_') str = str.substr(1);
+ if (str.startswith("set") || str.startswith("add"))
+ str = str.substr(3);
+ else
+ return false;
+
+ if (str.empty()) return true;
+ return !islower(str.front());
+}
+
+/// Check a message send to see if it's likely to cause a retain cycle.
+void Sema::checkRetainCycles(ObjCMessageExpr *msg) {
+ // Only check instance methods whose selector looks like a setter.
+ if (!msg->isInstanceMessage() || !isSetterLikeSelector(msg->getSelector()))
+ return;
+
+ // Try to find a variable that the receiver is strongly owned by.
+ RetainCycleOwner owner;
+ if (msg->getReceiverKind() == ObjCMessageExpr::Instance) {
+ if (!findRetainCycleOwner(msg->getInstanceReceiver(), owner))
+ return;
+ } else {
+ assert(msg->getReceiverKind() == ObjCMessageExpr::SuperInstance);
+ owner.Variable = getCurMethodDecl()->getSelfDecl();
+ owner.Loc = msg->getSuperLoc();
+ owner.Range = msg->getSuperLoc();
+ }
+
+ // Check whether the receiver is captured by any of the arguments.
+ for (unsigned i = 0, e = msg->getNumArgs(); i != e; ++i)
+ if (Expr *capturer = findCapturingExpr(*this, msg->getArg(i), owner))
+ return diagnoseRetainCycle(*this, capturer, owner);
+}
+
+/// Check a property assign to see if it's likely to cause a retain cycle.
+void Sema::checkRetainCycles(Expr *receiver, Expr *argument) {
+ RetainCycleOwner owner;
+ if (!findRetainCycleOwner(receiver, owner))
+ return;
+
+ if (Expr *capturer = findCapturingExpr(*this, argument, owner))
+ diagnoseRetainCycle(*this, capturer, owner);
+}
+
+bool Sema::checkUnsafeAssigns(SourceLocation Loc,
+ QualType LHS, Expr *RHS) {
+ Qualifiers::ObjCLifetime LT = LHS.getObjCLifetime();
+ if (LT != Qualifiers::OCL_Weak && LT != Qualifiers::OCL_ExplicitNone)
+ return false;
+ // strip off any implicit cast added to get to the one arc-specific
+ while (ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(RHS)) {
+ if (cast->getCastKind() == CK_ObjCConsumeObject) {
+ Diag(Loc, diag::warn_arc_retained_assign)
+ << (LT == Qualifiers::OCL_ExplicitNone)
+ << RHS->getSourceRange();
+ return true;
+ }
+ RHS = cast->getSubExpr();
+ }
+ return false;
+}
+
+void Sema::checkUnsafeExprAssigns(SourceLocation Loc,
+ Expr *LHS, Expr *RHS) {
+ QualType LHSType = LHS->getType();
+ if (checkUnsafeAssigns(Loc, LHSType, RHS))
+ return;
+ Qualifiers::ObjCLifetime LT = LHSType.getObjCLifetime();
+ // FIXME. Check for other life times.
+ if (LT != Qualifiers::OCL_None)
+ return;
+
+ if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(LHS)) {
+ if (PRE->isImplicitProperty())
+ return;
+ const ObjCPropertyDecl *PD = PRE->getExplicitProperty();
+ if (!PD)
+ return;
+
+ unsigned Attributes = PD->getPropertyAttributes();
+ if (Attributes & ObjCPropertyDecl::OBJC_PR_assign)
+ while (ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(RHS)) {
+ if (cast->getCastKind() == CK_ObjCConsumeObject) {
+ Diag(Loc, diag::warn_arc_retained_property_assign)
+ << RHS->getSourceRange();
+ return;
+ }
+ RHS = cast->getSubExpr();
+ }
+ }
+}
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index e328eeb0aa2b..b555c8a9aa1f 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -1676,6 +1676,34 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
// Fall through: conditions and statements can have expressions.
case Sema::PCC_ParenthesizedExpression:
+ if (SemaRef.getLangOptions().ObjCAutoRefCount &&
+ CCC == Sema::PCC_ParenthesizedExpression) {
+ // (__bridge <type>)<expression>
+ Builder.AddTypedTextChunk("__bridge");
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Builder.AddPlaceholderChunk("type");
+ Builder.AddChunk(CodeCompletionString::CK_RightParen);
+ Builder.AddPlaceholderChunk("expression");
+ Results.AddResult(Result(Builder.TakeString()));
+
+ // (__bridge_transfer <Objective-C type>)<expression>
+ Builder.AddTypedTextChunk("__bridge_transfer");
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Builder.AddPlaceholderChunk("Objective-C type");
+ Builder.AddChunk(CodeCompletionString::CK_RightParen);
+ Builder.AddPlaceholderChunk("expression");
+ Results.AddResult(Result(Builder.TakeString()));
+
+ // (__bridge_retained <CF type>)<expression>
+ Builder.AddTypedTextChunk("__bridge_retained");
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Builder.AddPlaceholderChunk("CF type");
+ Builder.AddChunk(CodeCompletionString::CK_RightParen);
+ Builder.AddPlaceholderChunk("expression");
+ Results.AddResult(Result(Builder.TakeString()));
+ }
+ // Fall through
+
case Sema::PCC_Expression: {
if (SemaRef.getLangOptions().CPlusPlus) {
// 'this', if we're in a non-static member function.
@@ -1828,7 +1856,8 @@ static const char *GetCompletionTypeString(QualType T,
CodeCompletionAllocator &Allocator) {
PrintingPolicy Policy(Context.PrintingPolicy);
Policy.AnonymousTagLocations = false;
-
+ Policy.SuppressStrongLifetime = true;
+
if (!T.getLocalQualifiers()) {
// Built-in type names are constant strings.
if (const BuiltinType *BT = dyn_cast<BuiltinType>(T))
@@ -1878,9 +1907,9 @@ static void AddResultTypeChunk(ASTContext &Context,
T = Context.getTypeDeclType(cast<TypeDecl>(Enumerator->getDeclContext()));
else if (isa<UnresolvedUsingValueDecl>(ND)) {
/* Do nothing: ignore unresolved using declarations*/
- } else if (ValueDecl *Value = dyn_cast<ValueDecl>(ND))
+ } else if (ValueDecl *Value = dyn_cast<ValueDecl>(ND)) {
T = Value->getType();
- else if (ObjCPropertyDecl *Property = dyn_cast<ObjCPropertyDecl>(ND))
+ } else if (ObjCPropertyDecl *Property = dyn_cast<ObjCPropertyDecl>(ND))
T = Property->getType();
if (T.isNull() || Context.hasSameType(T, Context.DependentTy))
@@ -1907,6 +1936,10 @@ static void MaybeAddSentinel(ASTContext &Context, NamedDecl *FunctionOrMethod,
static std::string FormatFunctionParameter(ASTContext &Context,
ParmVarDecl *Param,
bool SuppressName = false) {
+ PrintingPolicy Policy(Context.PrintingPolicy);
+ Policy.AnonymousTagLocations = false;
+ Policy.SuppressStrongLifetime = true;
+
bool ObjCMethodParam = isa<ObjCMethodDecl>(Param->getDeclContext());
if (Param->getType()->isDependentType() ||
!Param->getType()->isBlockPointerType()) {
@@ -1917,8 +1950,7 @@ static std::string FormatFunctionParameter(ASTContext &Context,
if (Param->getIdentifier() && !ObjCMethodParam && !SuppressName)
Result = Param->getIdentifier()->getName();
- Param->getType().getAsStringInternal(Result,
- Context.PrintingPolicy);
+ Param->getType().getAsStringInternal(Result, Policy);
if (ObjCMethodParam) {
Result = "(" + Result;
@@ -1968,8 +2000,7 @@ static std::string FormatFunctionParameter(ASTContext &Context,
// We were unable to find a FunctionProtoTypeLoc with parameter names
// for the block; just use the parameter type as a placeholder.
std::string Result;
- Param->getType().getUnqualifiedType().
- getAsStringInternal(Result, Context.PrintingPolicy);
+ Param->getType().getUnqualifiedType().getAsStringInternal(Result, Policy);
if (ObjCMethodParam) {
Result = "(" + Result;
@@ -1986,7 +2017,7 @@ static std::string FormatFunctionParameter(ASTContext &Context,
std::string Result;
QualType ResultType = Block->getTypePtr()->getResultType();
if (!ResultType->isVoidType())
- ResultType.getAsStringInternal(Result, Context.PrintingPolicy);
+ ResultType.getAsStringInternal(Result, Policy);
Result = '^' + Result;
if (!BlockProto || Block->getNumArgs() == 0) {
@@ -2071,6 +2102,9 @@ static void AddTemplateParameterChunks(ASTContext &Context,
unsigned MaxParameters = 0,
unsigned Start = 0,
bool InDefaultArg = false) {
+ PrintingPolicy Policy(Context.PrintingPolicy);
+ Policy.AnonymousTagLocations = false;
+
typedef CodeCompletionString::Chunk Chunk;
bool FirstParameter = true;
@@ -2098,8 +2132,7 @@ static void AddTemplateParameterChunks(ASTContext &Context,
= dyn_cast<NonTypeTemplateParmDecl>(*P)) {
if (NTTP->getIdentifier())
PlaceholderStr = NTTP->getIdentifier()->getName();
- NTTP->getType().getAsStringInternal(PlaceholderStr,
- Context.PrintingPolicy);
+ NTTP->getType().getAsStringInternal(PlaceholderStr, Policy);
HasDefaultArg = NTTP->hasDefaultArgument();
} else {
assert(isa<TemplateTemplateParmDecl>(*P));
@@ -2286,6 +2319,10 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S,
typedef CodeCompletionString::Chunk Chunk;
CodeCompletionBuilder Result(Allocator, Priority, Availability);
+ PrintingPolicy Policy(S.Context.PrintingPolicy);
+ Policy.AnonymousTagLocations = false;
+ Policy.SuppressStrongLifetime = true;
+
if (Kind == RK_Pattern) {
Pattern->Priority = Priority;
Pattern->Availability = Availability;
@@ -2470,7 +2507,7 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S,
if ((*P)->getType()->isBlockPointerType() && !DeclaringEntity)
Arg = FormatFunctionParameter(S.Context, *P, true);
else {
- (*P)->getType().getAsStringInternal(Arg, S.Context.PrintingPolicy);
+ (*P)->getType().getAsStringInternal(Arg, Policy);
Arg = "(" + Arg + ")";
if (IdentifierInfo *II = (*P)->getIdentifier())
if (DeclaringEntity || AllParametersAreInformative)
@@ -2519,7 +2556,10 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString(
Sema &S,
CodeCompletionAllocator &Allocator) const {
typedef CodeCompletionString::Chunk Chunk;
-
+ PrintingPolicy Policy(S.Context.PrintingPolicy);
+ Policy.AnonymousTagLocations = false;
+ Policy.SuppressStrongLifetime = true;
+
// FIXME: Set priority, availability appropriately.
CodeCompletionBuilder Result(Allocator, 1, CXAvailability_Available);
FunctionDecl *FDecl = getFunction();
@@ -2545,7 +2585,7 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString(
else
Result.AddTextChunk(
Result.getAllocator().CopyString(
- Proto->getResultType().getAsString(S.Context.PrintingPolicy)));
+ Proto->getResultType().getAsString(Policy)));
Result.AddChunk(Chunk(CodeCompletionString::CK_LeftParen));
unsigned NumParams = FDecl? FDecl->getNumParams() : Proto->getNumArgs();
@@ -2563,7 +2603,7 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString(
ArgType = Proto->getArgType(I);
}
- ArgType.getAsStringInternal(ArgString, S.Context.PrintingPolicy);
+ ArgType.getAsStringInternal(ArgString, Policy);
if (I == CurrentArg)
Result.AddChunk(Chunk(CodeCompletionString::CK_CurrentParameter,
@@ -3204,8 +3244,23 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE,
return;
}
+ enum CodeCompletionContext::Kind contextKind;
+
+ if (IsArrow) {
+ contextKind = CodeCompletionContext::CCC_ArrowMemberAccess;
+ }
+ else {
+ if (BaseType->isObjCObjectPointerType() ||
+ BaseType->isObjCObjectOrInterfaceType()) {
+ contextKind = CodeCompletionContext::CCC_ObjCPropertyAccess;
+ }
+ else {
+ contextKind = CodeCompletionContext::CCC_DotMemberAccess;
+ }
+ }
+
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
- CodeCompletionContext(CodeCompletionContext::CCC_MemberAccess,
+ CodeCompletionContext(contextKind,
BaseType),
&ResultBuilder::IsMember);
Results.EnterNewScope();
@@ -3431,10 +3486,17 @@ void Sema::CodeCompleteCase(Scope *S) {
}
Results.ExitScope();
- if (CodeCompleter->includeMacros())
+ //We need to make sure we're setting the right context,
+ //so only say we include macros if the code completer says we do
+ enum CodeCompletionContext::Kind kind = CodeCompletionContext::CCC_Other;
+ if (CodeCompleter->includeMacros()) {
AddMacroResults(PP, Results);
+ kind = CodeCompletionContext::CCC_OtherWithMacros;
+ }
+
+
HandleCodeCompleteResults(this, CodeCompleter,
- CodeCompletionContext::CCC_OtherWithMacros,
+ kind,
Results.data(),Results.size());
}
@@ -3786,6 +3848,10 @@ void Sema::CodeCompleteOperatorName(Scope *S) {
void Sema::CodeCompleteConstructorInitializer(Decl *ConstructorD,
CXXCtorInitializer** Initializers,
unsigned NumInitializers) {
+ PrintingPolicy Policy(Context.PrintingPolicy);
+ Policy.AnonymousTagLocations = false;
+ Policy.SuppressStrongLifetime = true;
+
CXXConstructorDecl *Constructor
= static_cast<CXXConstructorDecl *>(ConstructorD);
if (!Constructor)
@@ -3825,7 +3891,7 @@ void Sema::CodeCompleteConstructorInitializer(Decl *ConstructorD,
Builder.AddTypedTextChunk(
Results.getAllocator().CopyString(
- Base->getType().getAsString(Context.PrintingPolicy)));
+ Base->getType().getAsString(Policy)));
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddPlaceholderChunk("args");
Builder.AddChunk(CodeCompletionString::CK_RightParen);
@@ -3850,7 +3916,7 @@ void Sema::CodeCompleteConstructorInitializer(Decl *ConstructorD,
Builder.AddTypedTextChunk(
Builder.getAllocator().CopyString(
- Base->getType().getAsString(Context.PrintingPolicy)));
+ Base->getType().getAsString(Policy)));
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddPlaceholderChunk("args");
Builder.AddChunk(CodeCompletionString::CK_RightParen);
@@ -4126,18 +4192,24 @@ static bool ObjCPropertyFlagConflicts(unsigned Attributes, unsigned NewFlag) {
if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
(Attributes & (ObjCDeclSpec::DQ_PR_readwrite |
ObjCDeclSpec::DQ_PR_assign |
+ ObjCDeclSpec::DQ_PR_unsafe_unretained |
ObjCDeclSpec::DQ_PR_copy |
- ObjCDeclSpec::DQ_PR_retain)))
+ ObjCDeclSpec::DQ_PR_retain |
+ ObjCDeclSpec::DQ_PR_strong)))
return true;
- // Check for more than one of { assign, copy, retain }.
+ // Check for more than one of { assign, copy, retain, strong }.
unsigned AssignCopyRetMask = Attributes & (ObjCDeclSpec::DQ_PR_assign |
+ ObjCDeclSpec::DQ_PR_unsafe_unretained |
ObjCDeclSpec::DQ_PR_copy |
- ObjCDeclSpec::DQ_PR_retain);
+ ObjCDeclSpec::DQ_PR_retain|
+ ObjCDeclSpec::DQ_PR_strong);
if (AssignCopyRetMask &&
AssignCopyRetMask != ObjCDeclSpec::DQ_PR_assign &&
+ AssignCopyRetMask != ObjCDeclSpec::DQ_PR_unsafe_unretained &&
AssignCopyRetMask != ObjCDeclSpec::DQ_PR_copy &&
- AssignCopyRetMask != ObjCDeclSpec::DQ_PR_retain)
+ AssignCopyRetMask != ObjCDeclSpec::DQ_PR_retain &&
+ AssignCopyRetMask != ObjCDeclSpec::DQ_PR_strong)
return true;
return false;
@@ -4157,10 +4229,15 @@ void Sema::CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS) {
Results.AddResult(CodeCompletionResult("readonly"));
if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_assign))
Results.AddResult(CodeCompletionResult("assign"));
+ if (!ObjCPropertyFlagConflicts(Attributes,
+ ObjCDeclSpec::DQ_PR_unsafe_unretained))
+ Results.AddResult(CodeCompletionResult("unsafe_unretained"));
if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_readwrite))
Results.AddResult(CodeCompletionResult("readwrite"));
if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_retain))
Results.AddResult(CodeCompletionResult("retain"));
+ if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_strong))
+ Results.AddResult(CodeCompletionResult("strong"));
if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_copy))
Results.AddResult(CodeCompletionResult("copy"));
if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_nonatomic))
@@ -4522,6 +4599,7 @@ static ObjCInterfaceDecl *GetAssumedMessageSendExprType(Expr *E) {
if (Method->isInstanceMethod())
return llvm::StringSwitch<ObjCInterfaceDecl *>(Id->getName())
.Case("retain", IFace)
+ .Case("strong", IFace)
.Case("autorelease", IFace)
.Case("copy", IFace)
.Case("copyWithZone", IFace)
@@ -4878,7 +4956,7 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver,
bool AtArgumentExpression,
bool IsSuper) {
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
- CodeCompletionContext::CCC_Other);
+ CodeCompletionContext::CCC_ObjCClassMessage);
AddClassMessageCompletions(*this, S, Receiver, SelIdents, NumSelIdents,
AtArgumentExpression, IsSuper, Results);
@@ -4898,7 +4976,7 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver,
}
HandleCodeCompleteResults(this, CodeCompleter,
- CodeCompletionContext::CCC_Other,
+ CodeCompletionContext::CCC_ObjCClassMessage,
Results.data(), Results.size());
}
@@ -4941,7 +5019,7 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver,
// Build the set of methods we can see.
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
- CodeCompletionContext::CCC_Other);
+ CodeCompletionContext::CCC_ObjCInstanceMessage);
Results.EnterNewScope();
// If this is a send-to-super, try to add the special "super" send
@@ -5054,7 +5132,7 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver,
}
HandleCodeCompleteResults(this, CodeCompleter,
- CodeCompletionContext::CCC_Other,
+ CodeCompletionContext::CCC_ObjCInstanceMessage,
Results.data(),Results.size());
}
@@ -5245,8 +5323,7 @@ void Sema::CodeCompleteObjCInterfaceDecl(Scope *S) {
false, Results);
Results.ExitScope();
- // FIXME: Add a special context for this, use cached global completion
- // results.
+ // FIXME: Use cached global completion results.
HandleCodeCompleteResults(this, CodeCompleter,
CodeCompletionContext::CCC_Other,
Results.data(),Results.size());
@@ -5255,7 +5332,7 @@ void Sema::CodeCompleteObjCInterfaceDecl(Scope *S) {
void Sema::CodeCompleteObjCSuperclass(Scope *S, IdentifierInfo *ClassName,
SourceLocation ClassNameLoc) {
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
- CodeCompletionContext::CCC_Other);
+ CodeCompletionContext::CCC_ObjCSuperclass);
Results.EnterNewScope();
// Make sure that we ignore the class we're currently defining.
@@ -5269,10 +5346,9 @@ void Sema::CodeCompleteObjCSuperclass(Scope *S, IdentifierInfo *ClassName,
false, Results);
Results.ExitScope();
- // FIXME: Add a special context for this, use cached global completion
- // results.
+ // FIXME: Use cached global completion results.
HandleCodeCompleteResults(this, CodeCompleter,
- CodeCompletionContext::CCC_Other,
+ CodeCompletionContext::CCC_ObjCSuperclass,
Results.data(),Results.size());
}
@@ -5286,8 +5362,7 @@ void Sema::CodeCompleteObjCImplementationDecl(Scope *S) {
true, Results);
Results.ExitScope();
- // FIXME: Add a special context for this, use cached global completion
- // results.
+ // FIXME: Use cached global completion results.
HandleCodeCompleteResults(this, CodeCompleter,
CodeCompletionContext::CCC_Other,
Results.data(),Results.size());
@@ -5299,7 +5374,7 @@ void Sema::CodeCompleteObjCInterfaceCategory(Scope *S,
typedef CodeCompletionResult Result;
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
- CodeCompletionContext::CCC_Other);
+ CodeCompletionContext::CCC_ObjCCategoryName);
// Ignore any categories we find that have already been implemented by this
// interface.
@@ -5323,7 +5398,7 @@ void Sema::CodeCompleteObjCInterfaceCategory(Scope *S,
Results.ExitScope();
HandleCodeCompleteResults(this, CodeCompleter,
- CodeCompletionContext::CCC_Other,
+ CodeCompletionContext::CCC_ObjCCategoryName,
Results.data(),Results.size());
}
@@ -5342,7 +5417,7 @@ void Sema::CodeCompleteObjCImplementationCategory(Scope *S,
return CodeCompleteObjCInterfaceCategory(S, ClassName, ClassNameLoc);
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
- CodeCompletionContext::CCC_Other);
+ CodeCompletionContext::CCC_ObjCCategoryName);
// Add all of the categories that have have corresponding interface
// declarations in this class and any of its superclasses, except for
@@ -5363,7 +5438,7 @@ void Sema::CodeCompleteObjCImplementationCategory(Scope *S,
Results.ExitScope();
HandleCodeCompleteResults(this, CodeCompleter,
- CodeCompletionContext::CCC_Other,
+ CodeCompletionContext::CCC_ObjCCategoryName,
Results.data(),Results.size());
}
@@ -6273,6 +6348,7 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S,
Results.EnterNewScope();
PrintingPolicy Policy(Context.PrintingPolicy);
Policy.AnonymousTagLocations = false;
+ Policy.SuppressStrongLifetime = true;
for (KnownMethodsMap::iterator M = KnownMethods.begin(),
MEnd = KnownMethods.end();
M != MEnd; ++M) {
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 9446c0e8c03f..9d91a48bdcd7 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -45,7 +45,12 @@
using namespace clang;
using namespace sema;
-Sema::DeclGroupPtrTy Sema::ConvertDeclToDeclGroup(Decl *Ptr) {
+Sema::DeclGroupPtrTy Sema::ConvertDeclToDeclGroup(Decl *Ptr, Decl *OwnedType) {
+ if (OwnedType) {
+ Decl *Group[2] = { OwnedType, Ptr };
+ return DeclGroupPtrTy::make(DeclGroupRef::Create(Context, Group, 2));
+ }
+
return DeclGroupPtrTy::make(DeclGroupRef(Ptr));
}
@@ -287,41 +292,42 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II,
// There may have been a typo in the name of the type. Look up typo
// results, in case we have something that we can suggest.
- LookupResult Lookup(*this, &II, IILoc, LookupOrdinaryName,
- NotForRedeclaration);
+ if (TypoCorrection Corrected = CorrectTypo(DeclarationNameInfo(&II, IILoc),
+ LookupOrdinaryName, S, SS, NULL,
+ false, CTC_Type)) {
+ std::string CorrectedStr(Corrected.getAsString(getLangOptions()));
+ std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOptions()));
- if (DeclarationName Corrected = CorrectTypo(Lookup, S, SS, 0, 0, CTC_Type)) {
- if (NamedDecl *Result = Lookup.getAsSingle<NamedDecl>()) {
+ if (Corrected.isKeyword()) {
+ // We corrected to a keyword.
+ // FIXME: Actually recover with the keyword we suggest, and emit a fix-it.
+ Diag(IILoc, diag::err_unknown_typename_suggest)
+ << &II << CorrectedQuotedStr;
+ return true;
+ } else {
+ NamedDecl *Result = Corrected.getCorrectionDecl();
if ((isa<TypeDecl>(Result) || isa<ObjCInterfaceDecl>(Result)) &&
!Result->isInvalidDecl()) {
// We found a similarly-named type or interface; suggest that.
if (!SS || !SS->isSet())
Diag(IILoc, diag::err_unknown_typename_suggest)
- << &II << Lookup.getLookupName()
- << FixItHint::CreateReplacement(SourceRange(IILoc),
- Result->getNameAsString());
+ << &II << CorrectedQuotedStr
+ << FixItHint::CreateReplacement(SourceRange(IILoc), CorrectedStr);
else if (DeclContext *DC = computeDeclContext(*SS, false))
Diag(IILoc, diag::err_unknown_nested_typename_suggest)
- << &II << DC << Lookup.getLookupName() << SS->getRange()
- << FixItHint::CreateReplacement(SourceRange(IILoc),
- Result->getNameAsString());
+ << &II << DC << CorrectedQuotedStr << SS->getRange()
+ << FixItHint::CreateReplacement(SourceRange(IILoc), CorrectedStr);
else
llvm_unreachable("could not have corrected a typo here");
Diag(Result->getLocation(), diag::note_previous_decl)
- << Result->getDeclName();
+ << CorrectedQuotedStr;
SuggestedType = getTypeName(*Result->getIdentifier(), IILoc, S, SS,
false, false, ParsedType(),
/*NonTrivialTypeSourceInfo=*/true);
return true;
}
- } else if (Lookup.empty()) {
- // We corrected to a keyword.
- // FIXME: Actually recover with the keyword we suggest, and emit a fix-it.
- Diag(IILoc, diag::err_unknown_typename_suggest)
- << &II << Corrected;
- return true;
}
}
@@ -509,11 +515,15 @@ Corrected:
// Perform typo correction to determine if there is another name that is
// close to this name.
if (!SecondTry) {
- if (DeclarationName Corrected = CorrectTypo(Result, S, &SS)) {
+ SecondTry = true;
+ if (TypoCorrection Corrected = CorrectTypo(Result.getLookupNameInfo(),
+ Result.getLookupKind(), S, &SS)) {
unsigned UnqualifiedDiag = diag::err_undeclared_var_use_suggest;
unsigned QualifiedDiag = diag::err_no_member_suggest;
+ std::string CorrectedStr(Corrected.getAsString(getLangOptions()));
+ std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOptions()));
- NamedDecl *FirstDecl = Result.empty()? 0 : *Result.begin();
+ NamedDecl *FirstDecl = Corrected.getCorrectionDecl();
NamedDecl *UnderlyingFirstDecl
= FirstDecl? FirstDecl->getUnderlyingDecl() : 0;
if (getLangOptions().CPlusPlus && NextToken.is(tok::less) &&
@@ -527,26 +537,33 @@ Corrected:
UnqualifiedDiag = diag::err_unknown_typename_suggest;
QualifiedDiag = diag::err_unknown_nested_typename_suggest;
}
-
+
if (SS.isEmpty())
Diag(NameLoc, UnqualifiedDiag)
- << Name << Corrected
- << FixItHint::CreateReplacement(NameLoc, Corrected.getAsString());
+ << Name << CorrectedQuotedStr
+ << FixItHint::CreateReplacement(NameLoc, CorrectedStr);
else
Diag(NameLoc, QualifiedDiag)
- << Name << computeDeclContext(SS, false) << Corrected
+ << Name << computeDeclContext(SS, false) << CorrectedQuotedStr
<< SS.getRange()
- << FixItHint::CreateReplacement(NameLoc, Corrected.getAsString());
+ << FixItHint::CreateReplacement(NameLoc, CorrectedStr);
// Update the name, so that the caller has the new name.
- Name = Corrected.getAsIdentifierInfo();
+ Name = Corrected.getCorrectionAsIdentifierInfo();
+ // Also update the LookupResult...
+ // FIXME: This should probably go away at some point
+ Result.clear();
+ Result.setLookupName(Corrected.getCorrection());
+ if (FirstDecl) Result.addDecl(FirstDecl);
+
// Typo correction corrected to a keyword.
- if (Result.empty())
- return Corrected.getAsIdentifierInfo();
+ if (Corrected.isKeyword())
+ return Corrected.getCorrectionAsIdentifierInfo();
- Diag(FirstDecl->getLocation(), diag::note_previous_decl)
- << FirstDecl->getDeclName();
+ if (FirstDecl)
+ Diag(FirstDecl->getLocation(), diag::note_previous_decl)
+ << CorrectedQuotedStr;
// If we found an Objective-C instance variable, let
// LookupInObjCMethod build the appropriate expression to
@@ -1137,17 +1154,18 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
/// class could not be found.
ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *&Id,
SourceLocation IdLoc,
- bool TypoCorrection) {
+ bool DoTypoCorrection) {
// The third "scope" argument is 0 since we aren't enabling lazy built-in
// creation from this context.
NamedDecl *IDecl = LookupSingleName(TUScope, Id, IdLoc, LookupOrdinaryName);
- if (!IDecl && TypoCorrection) {
+ if (!IDecl && DoTypoCorrection) {
// Perform typo correction at the given location, but only if we
// find an Objective-C class name.
- LookupResult R(*this, Id, IdLoc, LookupOrdinaryName);
- if (CorrectTypo(R, TUScope, 0, 0, false, CTC_NoKeywords) &&
- (IDecl = R.getAsSingle<ObjCInterfaceDecl>())) {
+ TypoCorrection C;
+ if ((C = CorrectTypo(DeclarationNameInfo(Id, IdLoc), LookupOrdinaryName,
+ TUScope, NULL, NULL, false, CTC_NoKeywords)) &&
+ (IDecl = C.getCorrectionDeclAs<ObjCInterfaceDecl>())) {
Diag(IdLoc, diag::err_undef_interface_suggest)
<< Id << IDecl->getDeclName()
<< FixItHint::CreateReplacement(IdLoc, IDecl->getNameAsString());
@@ -1359,7 +1377,7 @@ void Sema::MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls) {
// The types match. Link up the redeclaration chain if the old
// declaration was a typedef.
- // FIXME: this is a potential source of wierdness if the type
+ // FIXME: this is a potential source of weirdness if the type
// spellings don't match exactly.
if (TypedefNameDecl *Typedef = dyn_cast<TypedefNameDecl>(Old))
New->setPreviousDeclaration(Typedef);
@@ -1527,7 +1545,8 @@ Sema::CXXSpecialMember Sema::getSpecialMember(const CXXMethodDecl *MD) {
/// GNU89 mode.
static bool canRedefineFunction(const FunctionDecl *FD,
const LangOptions& LangOpts) {
- return (LangOpts.GNUInline && !LangOpts.CPlusPlus &&
+ return ((FD->hasAttr<GNUInlineAttr>() || LangOpts.GNUInline) &&
+ !LangOpts.CPlusPlus &&
FD->isInlineSpecified() &&
FD->getStorageClass() == SC_Extern);
}
@@ -1927,6 +1946,7 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old) {
return false;
}
+
void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod,
const ObjCMethodDecl *oldMethod) {
// Merge the attributes.
@@ -2037,6 +2057,15 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
}
mergeDeclAttributes(New, Old, Context);
+ // Warn if an already-declared variable is made a weak_import in a subsequent declaration
+ if (New->getAttr<WeakImportAttr>() &&
+ Old->getStorageClass() == SC_None &&
+ !Old->getAttr<WeakImportAttr>()) {
+ Diag(New->getLocation(), diag::warn_weak_import) << New->getDeclName();
+ Diag(Old->getLocation(), diag::note_previous_definition);
+ // Remove weak_import attribute on new declaration.
+ New->dropAttr<WeakImportAttr>();
+ }
// Merge the types.
MergeVarDeclTypes(New, Old);
@@ -2597,7 +2626,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
}
// Mock up a declarator.
- Declarator Dc(DS, Declarator::TypeNameContext);
+ Declarator Dc(DS, Declarator::MemberContext);
TypeSourceInfo *TInfo = GetTypeForDeclarator(Dc, S);
assert(TInfo && "couldn't build declarator info for anonymous struct/union");
@@ -2736,6 +2765,7 @@ Sema::GetNameFromUnqualifiedId(const UnqualifiedId &Name) {
switch (Name.getKind()) {
+ case UnqualifiedId::IK_ImplicitSelfParam:
case UnqualifiedId::IK_Identifier:
NameInfo.setName(Name.Identifier);
NameInfo.setLoc(Name.StartLocation);
@@ -2924,10 +2954,9 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D,
return false;
}
-Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D,
- bool IsFunctionDefinition) {
+Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D) {
return HandleDeclarator(S, D, MultiTemplateParamsArg(*this),
- IsFunctionDefinition);
+ /*IsFunctionDefinition=*/false);
}
/// DiagnoseClassNameShadow - Implement C++ [class.mem]p13:
@@ -3274,8 +3303,18 @@ Sema::RegisterLocallyScopedExternCDecl(NamedDecl *ND,
if (S && IdResolver.ReplaceDecl(PrevDecl, ND)) {
// The previous declaration was found on the identifer resolver
// chain, so remove it from its scope.
- while (S && !S->isDeclScope(PrevDecl))
- S = S->getParent();
+
+ if (S->isDeclScope(PrevDecl)) {
+ // Special case for redeclarations in the SAME scope.
+ // Because this declaration is going to be added to the identifier chain
+ // later, we should temporarily take it OFF the chain.
+ IdResolver.RemoveDecl(ND);
+
+ } else {
+ // Find the scope for the original declaration.
+ while (S && !S->isDeclScope(PrevDecl))
+ S = S->getParent();
+ }
if (S)
S->RemoveDecl(PrevDecl);
@@ -3472,6 +3511,50 @@ static void SetNestedNameSpecifier(DeclaratorDecl *DD, Declarator &D) {
DD->setQualifierInfo(SS.getWithLocInContext(DD->getASTContext()));
}
+bool Sema::inferObjCARCLifetime(ValueDecl *decl) {
+ QualType type = decl->getType();
+ Qualifiers::ObjCLifetime lifetime = type.getObjCLifetime();
+ if (lifetime == Qualifiers::OCL_Autoreleasing) {
+ // Various kinds of declaration aren't allowed to be __autoreleasing.
+ unsigned kind = -1U;
+ if (VarDecl *var = dyn_cast<VarDecl>(decl)) {
+ if (var->hasAttr<BlocksAttr>())
+ kind = 0; // __block
+ else if (!var->hasLocalStorage())
+ kind = 1; // global
+ } else if (isa<ObjCIvarDecl>(decl)) {
+ kind = 3; // ivar
+ } else if (isa<FieldDecl>(decl)) {
+ kind = 2; // field
+ }
+
+ if (kind != -1U) {
+ Diag(decl->getLocation(), diag::err_arc_autoreleasing_var)
+ << kind;
+ }
+ } else if (lifetime == Qualifiers::OCL_None) {
+ // Try to infer lifetime.
+ if (!type->isObjCLifetimeType())
+ return false;
+
+ lifetime = type->getObjCARCImplicitLifetime();
+ type = Context.getLifetimeQualifiedType(type, lifetime);
+ decl->setType(type);
+ }
+
+ if (VarDecl *var = dyn_cast<VarDecl>(decl)) {
+ // Thread-local variables cannot have lifetime.
+ if (lifetime && lifetime != Qualifiers::OCL_ExplicitNone &&
+ var->isThreadSpecified()) {
+ Diag(var->getLocation(), diag::err_arc_thread_ownership)
+ << var->getType();
+ return true;
+ }
+ }
+
+ return false;
+}
+
NamedDecl*
Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
QualType R, TypeSourceInfo *TInfo,
@@ -3630,6 +3713,11 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// Handle attributes prior to checking for duplicates in MergeVarDecl
ProcessDeclAttributes(S, NewVD, D);
+ // In auto-retain/release, infer strong retension for variables of
+ // retainable type.
+ if (getLangOptions().ObjCAutoRefCount && inferObjCARCLifetime(NewVD))
+ NewVD->setInvalidDecl();
+
// Handle GNU asm-label extension (encoded as an attribute).
if (Expr *E = (Expr*)D.getAsmLabel()) {
// The parser guarantees this is a string.
@@ -4007,10 +4095,10 @@ bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
for (CXXBasePaths::decl_iterator I = Paths.found_decls_begin(),
E = Paths.found_decls_end(); I != E; ++I) {
if (CXXMethodDecl *OldMD = dyn_cast<CXXMethodDecl>(*I)) {
+ MD->addOverriddenMethod(OldMD->getCanonicalDecl());
if (!CheckOverridingFunctionReturnType(MD, OldMD) &&
!CheckOverridingFunctionExceptionSpec(MD, OldMD) &&
!CheckIfOverriddenFunctionIsMarkedFinal(MD, OldMD)) {
- MD->addOverriddenMethod(OldMD->getCanonicalDecl());
AddedAny = true;
}
}
@@ -4035,7 +4123,7 @@ static void DiagnoseInvalidRedeclaration(Sema &S, FunctionDecl *NewFD) {
}
NamedDecl*
-Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
+Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
QualType R, TypeSourceInfo *TInfo,
LookupResult &Previous,
MultiTemplateParamsArg TemplateParamLists,
@@ -4611,9 +4699,18 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// A storage-class-specifier shall not be specified in an explicit
// specialization (14.7.3)
if (SC != SC_None) {
- Diag(NewFD->getLocation(),
- diag::err_explicit_specialization_storage_class)
- << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc());
+ if (SC != NewFD->getStorageClass())
+ Diag(NewFD->getLocation(),
+ diag::err_explicit_specialization_inconsistent_storage_class)
+ << SC
+ << FixItHint::CreateRemoval(
+ D.getDeclSpec().getStorageClassSpecLoc());
+
+ else
+ Diag(NewFD->getLocation(),
+ diag::ext_explicit_specialization_storage_class)
+ << FixItHint::CreateRemoval(
+ D.getDeclSpec().getStorageClassSpecLoc());
}
} else if (isExplicitSpecialization && isa<CXXMethodDecl>(NewFD)) {
@@ -5208,12 +5305,8 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
VarDecl *VDecl = dyn_cast<VarDecl>(RealDecl);
if (!VDecl) {
- if (getLangOptions().CPlusPlus &&
- RealDecl->getLexicalDeclContext()->isRecord() &&
- isa<NamedDecl>(RealDecl))
- Diag(RealDecl->getLocation(), diag::err_member_initialization);
- else
- Diag(RealDecl->getLocation(), diag::err_illegal_initializer);
+ assert(!isa<FieldDecl>(RealDecl) && "field init shouldn't get here");
+ Diag(RealDecl->getLocation(), diag::err_illegal_initializer);
RealDecl->setInvalidDecl();
return;
}
@@ -5232,6 +5325,10 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
VDecl->setTypeSourceInfo(DeducedType);
VDecl->setType(DeducedType->getType());
+ // In ARC, infer lifetime.
+ if (getLangOptions().ObjCAutoRefCount && inferObjCARCLifetime(VDecl))
+ VDecl->setInvalidDecl();
+
// If this is a redeclaration, check that the type we just deduced matches
// the previously declared type.
if (VarDecl *Old = VDecl->getPreviousDeclaration())
@@ -5372,15 +5469,23 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
// We allow integer constant expressions in all cases.
} else if (T->isIntegralOrEnumerationType()) {
- if (!Init->isValueDependent()) {
- // Check whether the expression is a constant expression.
- llvm::APSInt Value;
- SourceLocation Loc;
- if (!Init->isIntegerConstantExpr(Value, Context, &Loc)) {
- Diag(Loc, diag::err_in_class_initializer_non_constant)
- << Init->getSourceRange();
- VDecl->setInvalidDecl();
- }
+ // Check whether the expression is a constant expression.
+ SourceLocation Loc;
+ if (Init->isValueDependent())
+ ; // Nothing to check.
+ else if (Init->isIntegerConstantExpr(Context, &Loc))
+ ; // Ok, it's an ICE!
+ else if (Init->isEvaluatable(Context)) {
+ // If we can constant fold the initializer through heroics, accept it,
+ // but report this as a use of an extension for -pedantic.
+ Diag(Loc, diag::ext_in_class_initializer_non_constant)
+ << Init->getSourceRange();
+ } else {
+ // Otherwise, this is some crazy unknown case. Report the issue at the
+ // location provided by the isIntegerConstantExpr failed check.
+ Diag(Loc, diag::err_in_class_initializer_non_constant)
+ << Init->getSourceRange();
+ VDecl->setInvalidDecl();
}
// We allow floating-point constants as an extension in C++03, and
@@ -5466,7 +5571,10 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
// Check any implicit conversions within the expression.
CheckImplicitConversions(Init, VDecl->getLocation());
-
+
+ if (!VDecl->isInvalidDecl())
+ checkUnsafeAssigns(VDecl->getLocation(), VDecl->getType(), Init);
+
Init = MaybeCreateExprWithCleanups(Init);
// Attach the initializer to the decl.
VDecl->setInit(Init);
@@ -5735,6 +5843,23 @@ void Sema::ActOnCXXForRangeDecl(Decl *D) {
void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
if (var->isInvalidDecl()) return;
+ // In ARC, don't allow jumps past the implicit initialization of a
+ // local retaining variable.
+ if (getLangOptions().ObjCAutoRefCount &&
+ var->hasLocalStorage()) {
+ switch (var->getType().getObjCLifetime()) {
+ case Qualifiers::OCL_None:
+ case Qualifiers::OCL_ExplicitNone:
+ case Qualifiers::OCL_Autoreleasing:
+ break;
+
+ case Qualifiers::OCL_Weak:
+ case Qualifiers::OCL_Strong:
+ getCurFunction()->setHasBranchProtectedScope();
+ break;
+ }
+ }
+
// All the following checks are C++ only.
if (!getLangOptions().CPlusPlus) return;
@@ -5874,21 +5999,13 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
DiagnoseFunctionSpecifiers(D);
- TagDecl *OwnedDecl = 0;
- TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S, &OwnedDecl);
+ TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);
QualType parmDeclType = TInfo->getType();
if (getLangOptions().CPlusPlus) {
// Check that there are no default arguments inside the type of this
// parameter.
CheckExtraCXXDefaultArguments(D);
-
- if (OwnedDecl && OwnedDecl->isDefinition()) {
- // C++ [dcl.fct]p6:
- // Types shall not be defined in return or parameter types.
- Diag(OwnedDecl->getLocation(), diag::err_type_defined_in_param_type)
- << Context.getTypeDeclType(OwnedDecl);
- }
// Parameter declarators cannot be qualified (C++ [dcl.meaning]p1).
if (D.getCXXScopeSpec().isSet()) {
@@ -6003,7 +6120,7 @@ void Sema::DiagnoseSizeOfParametersAndReturnValue(ParmVarDecl * const *Param,
// Warn if the return value is pass-by-value and larger than the specified
// threshold.
- if (ReturnTy->isPODType()) {
+ if (ReturnTy.isPODType(Context)) {
unsigned Size = Context.getTypeSizeInChars(ReturnTy).getQuantity();
if (Size > LangOpts.NumLargeByValueCopy)
Diag(D->getLocation(), diag::warn_return_value_size)
@@ -6014,7 +6131,7 @@ void Sema::DiagnoseSizeOfParametersAndReturnValue(ParmVarDecl * const *Param,
// threshold.
for (; Param != ParamEnd; ++Param) {
QualType T = (*Param)->getType();
- if (!T->isPODType())
+ if (!T.isPODType(Context))
continue;
unsigned Size = Context.getTypeSizeInChars(T).getQuantity();
if (Size > LangOpts.NumLargeByValueCopy)
@@ -6028,8 +6145,31 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc,
QualType T, TypeSourceInfo *TSInfo,
VarDecl::StorageClass StorageClass,
VarDecl::StorageClass StorageClassAsWritten) {
+ // In ARC, infer a lifetime qualifier for appropriate parameter types.
+ if (getLangOptions().ObjCAutoRefCount &&
+ T.getObjCLifetime() == Qualifiers::OCL_None &&
+ T->isObjCLifetimeType()) {
+
+ Qualifiers::ObjCLifetime lifetime;
+
+ // Special cases for arrays:
+ // - if it's const, use __unsafe_unretained
+ // - otherwise, it's an error
+ if (T->isArrayType()) {
+ if (!T.isConstQualified()) {
+ Diag(NameLoc, diag::err_arc_array_param_no_ownership)
+ << TSInfo->getTypeLoc().getSourceRange();
+ }
+ lifetime = Qualifiers::OCL_ExplicitNone;
+ } else {
+ lifetime = T->getObjCARCImplicitLifetime();
+ }
+ T = Context.getLifetimeQualifiedType(T, lifetime);
+ }
+
ParmVarDecl *New = ParmVarDecl::Create(Context, DC, StartLoc, NameLoc, Name,
- adjustParameterType(T), TSInfo,
+ Context.getAdjustedParameterType(T),
+ TSInfo,
StorageClass, StorageClassAsWritten,
0);
@@ -6318,6 +6458,10 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
// Implements C++ [basic.start.main]p5 and C99 5.1.2.2.3.
FD->setHasImplicitReturnZero(true);
WP.disableCheckFallThrough();
+ } else if (FD->hasAttr<NakedAttr>()) {
+ // If the function is marked 'naked', don't complain about missing return
+ // statements.
+ WP.disableCheckFallThrough();
}
// MSVC permits the use of pure specifier (=0) on function definition,
@@ -6364,7 +6508,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
// Verify that that gotos and switch cases don't jump into scopes illegally.
if (getCurFunction()->NeedsScopeChecking() &&
!dcl->isInvalidDecl() &&
- !hasAnyErrorsInThisFunction())
+ !hasAnyUnrecoverableErrorsInThisFunction())
DiagnoseInvalidJumps(Body);
if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(dcl)) {
@@ -6379,15 +6523,17 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
// been leftover. This ensures that these temporaries won't be picked up for
// deletion in some later function.
if (PP.getDiagnostics().hasErrorOccurred() ||
- PP.getDiagnostics().getSuppressAllDiagnostics())
+ PP.getDiagnostics().getSuppressAllDiagnostics()) {
ExprTemporaries.clear();
- else if (!isa<FunctionTemplateDecl>(dcl)) {
+ ExprNeedsCleanups = false;
+ } else if (!isa<FunctionTemplateDecl>(dcl)) {
// Since the body is valid, issue any analysis-based warnings that are
// enabled.
ActivePolicy = &WP;
}
assert(ExprTemporaries.empty() && "Leftover temporaries in function");
+ assert(!ExprNeedsCleanups && "Unaccounted cleanups in function");
}
if (!IsInstantiation)
@@ -6398,8 +6544,10 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
// If any errors have occurred, clear out any temporaries that may have
// been leftover. This ensures that these temporaries won't be picked up for
// deletion in some later function.
- if (getDiagnostics().hasErrorOccurred())
+ if (getDiagnostics().hasErrorOccurred()) {
ExprTemporaries.clear();
+ ExprNeedsCleanups = false;
+ }
return dcl;
}
@@ -6439,6 +6587,7 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
Declarator D(DS, Declarator::BlockContext);
D.AddTypeInfo(DeclaratorChunk::getFunction(false, false, SourceLocation(), 0,
0, 0, true, SourceLocation(),
+ SourceLocation(),
EST_None, SourceLocation(),
0, 0, 0, 0, Loc, Loc, D),
DS.getAttributes(),
@@ -6466,6 +6615,9 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
/// These attributes can apply both to implicitly-declared builtins
/// (like __builtin___printf_chk) or to library-declared functions
/// like NSLog or printf.
+///
+/// We need to check for duplicate attributes both here and where user-written
+/// attributes are applied to declarations.
void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
if (FD->isInvalidDecl())
return;
@@ -6499,9 +6651,9 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
FD->addAttr(::new (Context) ConstAttr(FD->getLocation(), Context));
}
- if (Context.BuiltinInfo.isNoThrow(BuiltinID))
+ if (Context.BuiltinInfo.isNoThrow(BuiltinID) && !FD->getAttr<NoThrowAttr>())
FD->addAttr(::new (Context) NoThrowAttr(FD->getLocation(), Context));
- if (Context.BuiltinInfo.isConst(BuiltinID))
+ if (Context.BuiltinInfo.isConst(BuiltinID) && !FD->getAttr<ConstAttr>())
FD->addAttr(::new (Context) ConstAttr(FD->getLocation(), Context));
}
@@ -7728,6 +7880,11 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
// FIXME: What to pass instead of TUScope?
ProcessDeclAttributes(TUScope, NewFD, *D);
+ // In auto-retain/release, infer strong retension for fields of
+ // retainable type.
+ if (getLangOptions().ObjCAutoRefCount && inferObjCARCLifetime(NewFD))
+ NewFD->setInvalidDecl();
+
if (T.isObjCGCWeak())
Diag(Loc, diag::warn_attribute_weak_on_field);
@@ -7761,6 +7918,21 @@ bool Sema::CheckNontrivialField(FieldDecl *FD) {
member = CXXDestructor;
if (member != CXXInvalid) {
+ if (getLangOptions().ObjCAutoRefCount && RDecl->hasObjectMember()) {
+ // Objective-C++ ARC: it is an error to have a non-trivial field of
+ // a union. However, system headers in Objective-C programs
+ // occasionally have Objective-C lifetime objects within unions,
+ // and rather than cause the program to fail, we make those
+ // members unavailable.
+ SourceLocation Loc = FD->getLocation();
+ if (getSourceManager().isInSystemHeader(Loc)) {
+ if (!FD->hasAttr<UnavailableAttr>())
+ FD->addAttr(new (Context) UnavailableAttr(Loc, Context,
+ "this system field has retaining ownership"));
+ return false;
+ }
+ }
+
Diag(FD->getLocation(), diag::err_illegal_union_or_anon_struct_member)
<< (int)FD->getParent()->isUnion() << FD->getDeclName() << member;
DiagnoseNontrivial(RT, member);
@@ -7913,6 +8085,21 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) {
return;
}
}
+
+ if (EltTy->isObjCLifetimeType()) {
+ switch (EltTy.getObjCLifetime()) {
+ case Qualifiers::OCL_None:
+ case Qualifiers::OCL_ExplicitNone:
+ break;
+
+ case Qualifiers::OCL_Autoreleasing:
+ case Qualifiers::OCL_Weak:
+ case Qualifiers::OCL_Strong:
+ Diag((*fi)->getLocation(), diag::note_nontrivial_objc_ownership)
+ << QT << EltTy.getObjCLifetime();
+ return;
+ }
+ }
}
assert(0 && "found no explanation for non-trivial member");
@@ -8022,6 +8209,10 @@ Decl *Sema::ActOnIvar(Scope *S,
if (D.isInvalidType())
NewID->setInvalidDecl();
+ // In ARC, infer 'retaining' for ivars of retainable type.
+ if (getLangOptions().ObjCAutoRefCount && inferObjCARCLifetime(NewID))
+ NewID->setInvalidDecl();
+
if (II) {
// FIXME: When interfaces are DeclContexts, we'll need to add
// these to the interface.
@@ -8093,6 +8284,7 @@ void Sema::ActOnFields(Scope* S,
llvm::SmallVector<FieldDecl*, 32> RecFields;
RecordDecl *Record = dyn_cast<RecordDecl>(EnclosingDecl);
+ bool ARCErrReported = false;
for (unsigned i = 0; i != NumFields; ++i) {
FieldDecl *FD = cast<FieldDecl>(Fields[i]);
@@ -8158,7 +8350,7 @@ void Sema::ActOnFields(Scope* S,
continue;
}
if (!FD->getType()->isDependentType() &&
- !Context.getBaseElementType(FD->getType())->isPODType()) {
+ !Context.getBaseElementType(FD->getType()).isPODType(Context)) {
Diag(FD->getLocation(), diag::err_flexible_array_has_nonpod_type)
<< FD->getDeclName() << FD->getType();
FD->setInvalidDecl();
@@ -8205,17 +8397,45 @@ void Sema::ActOnFields(Scope* S,
FD->setInvalidDecl();
EnclosingDecl->setInvalidDecl();
continue;
- } else if (getLangOptions().ObjC1 &&
+ }
+ else if (!getLangOptions().CPlusPlus) {
+ if (getLangOptions().ObjCAutoRefCount && Record && !ARCErrReported) {
+ // It's an error in ARC if a field has lifetime.
+ // We don't want to report this in a system header, though,
+ // so we just make the field unavailable.
+ // FIXME: that's really not sufficient; we need to make the type
+ // itself invalid to, say, initialize or copy.
+ QualType T = FD->getType();
+ Qualifiers::ObjCLifetime lifetime = T.getObjCLifetime();
+ if (lifetime && lifetime != Qualifiers::OCL_ExplicitNone) {
+ SourceLocation loc = FD->getLocation();
+ if (getSourceManager().isInSystemHeader(loc)) {
+ if (!FD->hasAttr<UnavailableAttr>()) {
+ FD->addAttr(new (Context) UnavailableAttr(loc, Context,
+ "this system field has retaining ownership"));
+ }
+ } else {
+ Diag(FD->getLocation(), diag::err_arc_objc_object_in_struct);
+ }
+ ARCErrReported = true;
+ }
+ }
+ else if (getLangOptions().ObjC1 &&
getLangOptions().getGCMode() != LangOptions::NonGC &&
- Record &&
- (FD->getType()->isObjCObjectPointerType() ||
- FD->getType().isObjCGCStrong()))
- Record->setHasObjectMember(true);
- else if (Context.getAsArrayType(FD->getType())) {
- QualType BaseType = Context.getBaseElementType(FD->getType());
- if (Record && BaseType->isRecordType() &&
- BaseType->getAs<RecordType>()->getDecl()->hasObjectMember())
- Record->setHasObjectMember(true);
+ Record && !Record->hasObjectMember()) {
+ if (FD->getType()->isObjCObjectPointerType() ||
+ FD->getType().isObjCGCStrong())
+ Record->setHasObjectMember(true);
+ else if (Context.getAsArrayType(FD->getType())) {
+ QualType BaseType = Context.getBaseElementType(FD->getType());
+ if (BaseType->isRecordType() &&
+ BaseType->getAs<RecordType>()->getDecl()->hasObjectMember())
+ Record->setHasObjectMember(true);
+ else if (BaseType->isObjCObjectPointerType() ||
+ BaseType.isObjCGCStrong())
+ Record->setHasObjectMember(true);
+ }
+ }
}
// Keep track of the number of named members.
if (FD->getIdentifier())
@@ -8234,6 +8454,42 @@ void Sema::ActOnFields(Scope* S,
Convs->setAccess(I, (*I)->getAccess());
if (!CXXRecord->isDependentType()) {
+ // 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.
+ //
+ // This rule is also handled by CXXRecordDecl::completeDefinition().
+ // However, here we check whether this particular class is only
+ // non-POD because of the presence of an Objective-C pointer member.
+ // If so, objects of this type cannot be shared between code compiled
+ // with instant objects and code compiled with manual retain/release.
+ if (getLangOptions().ObjCAutoRefCount &&
+ CXXRecord->hasObjectMember() &&
+ CXXRecord->getLinkage() == ExternalLinkage) {
+ if (CXXRecord->isPOD()) {
+ Diag(CXXRecord->getLocation(),
+ diag::warn_arc_non_pod_class_with_object_member)
+ << CXXRecord;
+ } else {
+ // FIXME: Fix-Its would be nice here, but finding a good location
+ // for them is going to be tricky.
+ if (CXXRecord->hasTrivialCopyConstructor())
+ Diag(CXXRecord->getLocation(),
+ diag::warn_arc_trivial_member_function_with_object_member)
+ << CXXRecord << 0;
+ if (CXXRecord->hasTrivialCopyAssignment())
+ Diag(CXXRecord->getLocation(),
+ diag::warn_arc_trivial_member_function_with_object_member)
+ << CXXRecord << 1;
+ if (CXXRecord->hasTrivialDestructor())
+ Diag(CXXRecord->getLocation(),
+ diag::warn_arc_trivial_member_function_with_object_member)
+ << CXXRecord << 2;
+ }
+ }
+
// Adjust user-defined destructor exception spec.
if (getLangOptions().CPlusPlus0x &&
CXXRecord->hasUserDeclaredDestructor())
@@ -8807,7 +9063,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
// Adjust the Expr initializer and type.
if (ECD->getInitExpr() &&
- !Context.hasSameType(NewTy, ECD->getInitExpr()->getType()))
+ !Context.hasSameType(NewTy, ECD->getInitExpr()->getType()))
ECD->setInitExpr(ImplicitCastExpr::Create(Context, NewTy,
CK_IntegralCast,
ECD->getInitExpr(),
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 7f93ab72d6d1..61b7b3ee05e3 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -17,6 +17,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
+#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/DelayedDiagnostic.h"
@@ -48,14 +49,14 @@ enum {
// Helper functions
//===----------------------------------------------------------------------===//
-static const FunctionType *getFunctionType(const Decl *d,
+static const FunctionType *getFunctionType(const Decl *D,
bool blocksToo = true) {
QualType Ty;
- if (const ValueDecl *decl = dyn_cast<ValueDecl>(d))
+ if (const ValueDecl *decl = dyn_cast<ValueDecl>(D))
Ty = decl->getType();
- else if (const FieldDecl *decl = dyn_cast<FieldDecl>(d))
+ else if (const FieldDecl *decl = dyn_cast<FieldDecl>(D))
Ty = decl->getType();
- else if (const TypedefNameDecl* decl = dyn_cast<TypedefNameDecl>(d))
+ else if (const TypedefNameDecl* decl = dyn_cast<TypedefNameDecl>(D))
Ty = decl->getUnderlyingType();
else
return 0;
@@ -73,46 +74,47 @@ static const FunctionType *getFunctionType(const Decl *d,
/// isFunction - Return true if the given decl has function
/// type (function or function-typed variable).
-static bool isFunction(const Decl *d) {
- return getFunctionType(d, false) != NULL;
+static bool isFunction(const Decl *D) {
+ return getFunctionType(D, false) != NULL;
}
/// isFunctionOrMethod - Return true if the given decl has function
/// type (function or function-typed variable) or an Objective-C
/// method.
-static bool isFunctionOrMethod(const Decl *d) {
- return isFunction(d)|| isa<ObjCMethodDecl>(d);
+static bool isFunctionOrMethod(const Decl *D) {
+ return isFunction(D)|| isa<ObjCMethodDecl>(D);
}
/// isFunctionOrMethodOrBlock - Return true if the given decl has function
/// type (function or function-typed variable) or an Objective-C
/// method or a block.
-static bool isFunctionOrMethodOrBlock(const Decl *d) {
- if (isFunctionOrMethod(d))
+static bool isFunctionOrMethodOrBlock(const Decl *D) {
+ if (isFunctionOrMethod(D))
return true;
// check for block is more involved.
- if (const VarDecl *V = dyn_cast<VarDecl>(d)) {
+ if (const VarDecl *V = dyn_cast<VarDecl>(D)) {
QualType Ty = V->getType();
return Ty->isBlockPointerType();
}
- return isa<BlockDecl>(d);
+ return isa<BlockDecl>(D);
}
/// Return true if the given decl has a declarator that should have
/// been processed by Sema::GetTypeForDeclarator.
-static bool hasDeclarator(const Decl *d) {
- // In some sense, TypedefNameDecl really *ought* to be a DeclaratorDecl.
- return isa<DeclaratorDecl>(d) || isa<BlockDecl>(d) || isa<TypedefNameDecl>(d);
+static bool hasDeclarator(const Decl *D) {
+ // In some sense, TypedefDecl really *ought* to be a DeclaratorDecl.
+ return isa<DeclaratorDecl>(D) || isa<BlockDecl>(D) || isa<TypedefNameDecl>(D) ||
+ isa<ObjCPropertyDecl>(D);
}
/// hasFunctionProto - Return true if the given decl has a argument
/// information. This decl should have already passed
/// isFunctionOrMethod or isFunctionOrMethodOrBlock.
-static bool hasFunctionProto(const Decl *d) {
- if (const FunctionType *FnTy = getFunctionType(d))
+static bool hasFunctionProto(const Decl *D) {
+ if (const FunctionType *FnTy = getFunctionType(D))
return isa<FunctionProtoType>(FnTy);
else {
- assert(isa<ObjCMethodDecl>(d) || isa<BlockDecl>(d));
+ assert(isa<ObjCMethodDecl>(D) || isa<BlockDecl>(D));
return true;
}
}
@@ -120,42 +122,42 @@ static bool hasFunctionProto(const Decl *d) {
/// getFunctionOrMethodNumArgs - Return number of function or method
/// arguments. It is an error to call this on a K&R function (use
/// hasFunctionProto first).
-static unsigned getFunctionOrMethodNumArgs(const Decl *d) {
- if (const FunctionType *FnTy = getFunctionType(d))
+static unsigned getFunctionOrMethodNumArgs(const Decl *D) {
+ if (const FunctionType *FnTy = getFunctionType(D))
return cast<FunctionProtoType>(FnTy)->getNumArgs();
- if (const BlockDecl *BD = dyn_cast<BlockDecl>(d))
+ if (const BlockDecl *BD = dyn_cast<BlockDecl>(D))
return BD->getNumParams();
- return cast<ObjCMethodDecl>(d)->param_size();
+ return cast<ObjCMethodDecl>(D)->param_size();
}
-static QualType getFunctionOrMethodArgType(const Decl *d, unsigned Idx) {
- if (const FunctionType *FnTy = getFunctionType(d))
+static QualType getFunctionOrMethodArgType(const Decl *D, unsigned Idx) {
+ if (const FunctionType *FnTy = getFunctionType(D))
return cast<FunctionProtoType>(FnTy)->getArgType(Idx);
- if (const BlockDecl *BD = dyn_cast<BlockDecl>(d))
+ if (const BlockDecl *BD = dyn_cast<BlockDecl>(D))
return BD->getParamDecl(Idx)->getType();
- return cast<ObjCMethodDecl>(d)->param_begin()[Idx]->getType();
+ return cast<ObjCMethodDecl>(D)->param_begin()[Idx]->getType();
}
-static QualType getFunctionOrMethodResultType(const Decl *d) {
- if (const FunctionType *FnTy = getFunctionType(d))
+static QualType getFunctionOrMethodResultType(const Decl *D) {
+ if (const FunctionType *FnTy = getFunctionType(D))
return cast<FunctionProtoType>(FnTy)->getResultType();
- return cast<ObjCMethodDecl>(d)->getResultType();
+ return cast<ObjCMethodDecl>(D)->getResultType();
}
-static bool isFunctionOrMethodVariadic(const Decl *d) {
- if (const FunctionType *FnTy = getFunctionType(d)) {
+static bool isFunctionOrMethodVariadic(const Decl *D) {
+ if (const FunctionType *FnTy = getFunctionType(D)) {
const FunctionProtoType *proto = cast<FunctionProtoType>(FnTy);
return proto->isVariadic();
- } else if (const BlockDecl *BD = dyn_cast<BlockDecl>(d))
+ } else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D))
return BD->isVariadic();
else {
- return cast<ObjCMethodDecl>(d)->isVariadic();
+ return cast<ObjCMethodDecl>(D)->isVariadic();
}
}
-static bool isInstanceMethod(const Decl *d) {
- if (const CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(d))
+static bool isInstanceMethod(const Decl *D) {
+ if (const CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(D))
return MethodDecl->isInstance();
return false;
}
@@ -192,6 +194,16 @@ static inline bool isCFStringType(QualType T, ASTContext &Ctx) {
return RD->getIdentifier() == &Ctx.Idents.get("__CFString");
}
+static bool checkAttributeNumArgs(Sema &S, const AttributeList &Attr,
+ unsigned int Num) {
+ if (Attr.getNumArgs() != Num) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << Num;
+ return false;
+ }
+
+ return true;
+}
+
//===----------------------------------------------------------------------===//
// Attribute Implementations
//===----------------------------------------------------------------------===//
@@ -200,9 +212,9 @@ static inline bool isCFStringType(QualType T, ASTContext &Ctx) {
// least add some helper functions to check most argument patterns (#
// and types of args).
-static void HandleExtVectorTypeAttr(Scope *scope, Decl *d,
- const AttributeList &Attr, Sema &S) {
- TypedefNameDecl *tDecl = dyn_cast<TypedefNameDecl>(d);
+static void handleExtVectorTypeAttr(Sema &S, Scope *scope, Decl *D,
+ const AttributeList &Attr) {
+ TypedefNameDecl *tDecl = dyn_cast<TypedefNameDecl>(D);
if (tDecl == 0) {
S.Diag(Attr.getLoc(), diag::err_typecheck_ext_vector_not_typedef);
return;
@@ -217,13 +229,17 @@ static void HandleExtVectorTypeAttr(Scope *scope, Decl *d,
CXXScopeSpec SS;
UnqualifiedId id;
id.setIdentifier(Attr.getParameterName(), Attr.getLoc());
- sizeExpr = S.ActOnIdExpression(scope, SS, id, false, false).takeAs<Expr>();
+
+ ExprResult Size = S.ActOnIdExpression(scope, SS, id, false, false);
+ if (Size.isInvalid())
+ return;
+
+ sizeExpr = Size.get();
} else {
// check the attribute arguments.
- if (Attr.getNumArgs() != 1) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ if (!checkAttributeNumArgs(S, Attr, 1))
return;
- }
+
sizeExpr = Attr.getArg(0);
}
@@ -239,16 +255,14 @@ static void HandleExtVectorTypeAttr(Scope *scope, Decl *d,
}
}
-static void HandlePackedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handlePackedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
- if (Attr.getNumArgs() > 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ if (!checkAttributeNumArgs(S, Attr, 0))
return;
- }
- if (TagDecl *TD = dyn_cast<TagDecl>(d))
+ if (TagDecl *TD = dyn_cast<TagDecl>(D))
TD->addAttr(::new (S.Context) PackedAttr(Attr.getLoc(), S.Context));
- else if (FieldDecl *FD = dyn_cast<FieldDecl>(d)) {
+ else if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
// If the alignment is less than or equal to 8 bits, the packed attribute
// has no effect.
if (!FD->getType()->isIncompleteType() &&
@@ -261,49 +275,45 @@ static void HandlePackedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
}
-static void HandleMsStructAttr(Decl *d, const AttributeList &Attr, Sema &S) {
- if (TagDecl *TD = dyn_cast<TagDecl>(d))
+static void handleMsStructAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (TagDecl *TD = dyn_cast<TagDecl>(D))
TD->addAttr(::new (S.Context) MsStructAttr(Attr.getLoc(), S.Context));
else
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
}
-static void HandleIBAction(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleIBAction(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
- if (Attr.getNumArgs() > 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ if (!checkAttributeNumArgs(S, Attr, 0))
return;
- }
// The IBAction attributes only apply to instance methods.
- if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(d))
+ if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
if (MD->isInstanceMethod()) {
- d->addAttr(::new (S.Context) IBActionAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) IBActionAttr(Attr.getLoc(), S.Context));
return;
}
S.Diag(Attr.getLoc(), diag::warn_attribute_ibaction) << Attr.getName();
}
-static void HandleIBOutlet(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleIBOutlet(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
- if (Attr.getNumArgs() > 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ if (!checkAttributeNumArgs(S, Attr, 0))
return;
- }
// The IBOutlet attributes only apply to instance variables of
// Objective-C classes.
- if (isa<ObjCIvarDecl>(d) || isa<ObjCPropertyDecl>(d)) {
- d->addAttr(::new (S.Context) IBOutletAttr(Attr.getLoc(), S.Context));
+ if (isa<ObjCIvarDecl>(D) || isa<ObjCPropertyDecl>(D)) {
+ D->addAttr(::new (S.Context) IBOutletAttr(Attr.getLoc(), S.Context));
return;
}
S.Diag(Attr.getLoc(), diag::warn_attribute_iboutlet) << Attr.getName();
}
-static void HandleIBOutletCollection(Decl *d, const AttributeList &Attr,
- Sema &S) {
+static void handleIBOutletCollection(Sema &S, Decl *D,
+ const AttributeList &Attr) {
// The iboutletcollection attribute can have zero or one arguments.
if (Attr.getParameterName() && Attr.getNumArgs() > 0) {
@@ -313,17 +323,17 @@ static void HandleIBOutletCollection(Decl *d, const AttributeList &Attr,
// The IBOutletCollection attributes only apply to instance variables of
// Objective-C classes.
- if (!(isa<ObjCIvarDecl>(d) || isa<ObjCPropertyDecl>(d))) {
+ if (!(isa<ObjCIvarDecl>(D) || isa<ObjCPropertyDecl>(D))) {
S.Diag(Attr.getLoc(), diag::warn_attribute_iboutlet) << Attr.getName();
return;
}
- if (const ValueDecl *VD = dyn_cast<ValueDecl>(d))
+ if (const ValueDecl *VD = dyn_cast<ValueDecl>(D))
if (!VD->getType()->getAs<ObjCObjectPointerType>()) {
S.Diag(Attr.getLoc(), diag::err_iboutletcollection_object_type)
<< VD->getType() << 0;
return;
}
- if (const ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(d))
+ if (const ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D))
if (!PD->getType()->getAs<ObjCObjectPointerType>()) {
S.Diag(Attr.getLoc(), diag::err_iboutletcollection_object_type)
<< PD->getType() << 1;
@@ -335,7 +345,7 @@ static void HandleIBOutletCollection(Decl *d, const AttributeList &Attr,
II = &S.Context.Idents.get("id");
ParsedType TypeRep = S.getTypeName(*II, Attr.getLoc(),
- S.getScopeForContext(d->getDeclContext()->getParent()));
+ S.getScopeForContext(D->getDeclContext()->getParent()));
if (!TypeRep) {
S.Diag(Attr.getLoc(), diag::err_iboutletcollection_type) << II;
return;
@@ -350,14 +360,29 @@ static void HandleIBOutletCollection(Decl *d, const AttributeList &Attr,
S.Diag(Attr.getLoc(), diag::err_iboutletcollection_type) << II;
return;
}
- d->addAttr(::new (S.Context) IBOutletCollectionAttr(Attr.getLoc(), S.Context,
+ D->addAttr(::new (S.Context) IBOutletCollectionAttr(Attr.getLoc(), S.Context,
QT));
}
-static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void possibleTransparentUnionPointerType(QualType &T) {
+ if (const RecordType *UT = T->getAsUnionType())
+ if (UT && UT->getDecl()->hasAttr<TransparentUnionAttr>()) {
+ RecordDecl *UD = UT->getDecl();
+ for (RecordDecl::field_iterator it = UD->field_begin(),
+ itend = UD->field_end(); it != itend; ++it) {
+ QualType QT = it->getType();
+ if (QT->isAnyPointerType() || QT->isBlockPointerType()) {
+ T = QT;
+ return;
+ }
+ }
+ }
+}
+
+static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// GCC ignores the nonnull attribute on K&R style function prototypes, so we
// ignore it as well
- if (!isFunctionOrMethod(d) || !hasFunctionProto(d)) {
+ if (!isFunctionOrMethod(D) || !hasFunctionProto(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
return;
@@ -365,8 +390,8 @@ static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// In C++ the implicit 'this' function parameter also counts, and they are
// counted from one.
- bool HasImplicitThisParam = isInstanceMethod(d);
- unsigned NumArgs = getFunctionOrMethodNumArgs(d) + HasImplicitThisParam;
+ bool HasImplicitThisParam = isInstanceMethod(D);
+ unsigned NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam;
// The nonnull attribute only applies to pointers.
llvm::SmallVector<unsigned, 10> NonNullArgs;
@@ -405,7 +430,9 @@ static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) {
}
// Is the function argument a pointer type?
- QualType T = getFunctionOrMethodArgType(d, x).getNonReferenceType();
+ QualType T = getFunctionOrMethodArgType(D, x).getNonReferenceType();
+ possibleTransparentUnionPointerType(T);
+
if (!T->isAnyPointerType() && !T->isBlockPointerType()) {
// FIXME: Should also highlight argument in decl.
S.Diag(Attr.getLoc(), diag::warn_nonnull_pointers_only)
@@ -419,23 +446,11 @@ static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// If no arguments were specified to __attribute__((nonnull)) then all pointer
// arguments have a nonnull attribute.
if (NonNullArgs.empty()) {
- for (unsigned I = 0, E = getFunctionOrMethodNumArgs(d); I != E; ++I) {
- QualType T = getFunctionOrMethodArgType(d, I).getNonReferenceType();
+ for (unsigned I = 0, E = getFunctionOrMethodNumArgs(D); I != E; ++I) {
+ QualType T = getFunctionOrMethodArgType(D, I).getNonReferenceType();
+ possibleTransparentUnionPointerType(T);
if (T->isAnyPointerType() || T->isBlockPointerType())
NonNullArgs.push_back(I);
- else if (const RecordType *UT = T->getAsUnionType()) {
- if (UT && UT->getDecl()->hasAttr<TransparentUnionAttr>()) {
- RecordDecl *UD = UT->getDecl();
- for (RecordDecl::field_iterator it = UD->field_begin(),
- itend = UD->field_end(); it != itend; ++it) {
- T = it->getType();
- if (T->isAnyPointerType() || T->isBlockPointerType()) {
- NonNullArgs.push_back(I);
- break;
- }
- }
- }
- }
}
// No pointer arguments?
@@ -451,11 +466,11 @@ static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) {
unsigned* start = &NonNullArgs[0];
unsigned size = NonNullArgs.size();
llvm::array_pod_sort(start, start + size);
- d->addAttr(::new (S.Context) NonNullAttr(Attr.getLoc(), S.Context, start,
+ D->addAttr(::new (S.Context) NonNullAttr(Attr.getLoc(), S.Context, start,
size));
}
-static void HandleOwnershipAttr(Decl *d, const AttributeList &AL, Sema &S) {
+static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) {
// This attribute must be applied to a function declaration.
// The first argument to the attribute must be a string,
// the name of the resource, for example "malloc".
@@ -500,7 +515,7 @@ static void HandleOwnershipAttr(Decl *d, const AttributeList &AL, Sema &S) {
llvm_unreachable("Unknown ownership attribute");
}
- if (!isFunction(d) || !hasFunctionProto(d)) {
+ if (!isFunction(D) || !hasFunctionProto(D)) {
S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type)
<< AL.getName() << ExpectedFunction;
return;
@@ -508,8 +523,8 @@ static void HandleOwnershipAttr(Decl *d, const AttributeList &AL, Sema &S) {
// In C++ the implicit 'this' function parameter also counts, and they are
// counted from one.
- bool HasImplicitThisParam = isInstanceMethod(d);
- unsigned NumArgs = getFunctionOrMethodNumArgs(d) + HasImplicitThisParam;
+ bool HasImplicitThisParam = isInstanceMethod(D);
+ unsigned NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam;
llvm::StringRef Module = AL.getParameterName()->getName();
@@ -552,7 +567,7 @@ static void HandleOwnershipAttr(Decl *d, const AttributeList &AL, Sema &S) {
case OwnershipAttr::Takes:
case OwnershipAttr::Holds: {
// Is the function argument a pointer type?
- QualType T = getFunctionOrMethodArgType(d, x);
+ QualType T = getFunctionOrMethodArgType(D, x);
if (!T->isAnyPointerType() && !T->isBlockPointerType()) {
// FIXME: Should also highlight argument in decl.
S.Diag(AL.getLoc(), diag::err_ownership_type)
@@ -584,8 +599,8 @@ static void HandleOwnershipAttr(Decl *d, const AttributeList &AL, Sema &S) {
// Check we don't have a conflict with another ownership attribute.
for (specific_attr_iterator<OwnershipAttr>
- i = d->specific_attr_begin<OwnershipAttr>(),
- e = d->specific_attr_end<OwnershipAttr>();
+ i = D->specific_attr_begin<OwnershipAttr>(),
+ e = D->specific_attr_end<OwnershipAttr>();
i != e; ++i) {
if ((*i)->getOwnKind() != K) {
for (const unsigned *I = (*i)->args_begin(), *E = (*i)->args_end();
@@ -609,7 +624,7 @@ static void HandleOwnershipAttr(Decl *d, const AttributeList &AL, Sema &S) {
return;
}
- d->addAttr(::new (S.Context) OwnershipAttr(AL.getLoc(), S.Context, K, Module,
+ D->addAttr(::new (S.Context) OwnershipAttr(AL.getLoc(), S.Context, K, Module,
start, size));
}
@@ -633,20 +648,20 @@ static bool hasEffectivelyInternalLinkage(NamedDecl *D) {
return false;
}
-static void HandleWeakRefAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleWeakRefAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// Check the attribute arguments.
if (Attr.getNumArgs() > 1) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
return;
}
- if (!isa<VarDecl>(d) && !isa<FunctionDecl>(d)) {
+ if (!isa<VarDecl>(D) && !isa<FunctionDecl>(D)) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedVariableOrFunction;
return;
}
- NamedDecl *nd = cast<NamedDecl>(d);
+ NamedDecl *nd = cast<NamedDecl>(D);
// gcc rejects
// class c {
@@ -658,7 +673,7 @@ static void HandleWeakRefAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// static int a __attribute__((weakref ("v2")));
// }
// we reject them
- const DeclContext *Ctx = d->getDeclContext()->getRedeclContext();
+ const DeclContext *Ctx = D->getDeclContext()->getRedeclContext();
if (!Ctx->isFileContext()) {
S.Diag(Attr.getLoc(), diag::err_attribute_weakref_not_global_context) <<
nd->getNameAsString();
@@ -704,14 +719,14 @@ static void HandleWeakRefAttr(Decl *d, const AttributeList &Attr, Sema &S) {
}
// GCC will accept anything as the argument of weakref. Should we
// check for an existing decl?
- d->addAttr(::new (S.Context) AliasAttr(Attr.getLoc(), S.Context,
+ D->addAttr(::new (S.Context) AliasAttr(Attr.getLoc(), S.Context,
Str->getString()));
}
- d->addAttr(::new (S.Context) WeakRefAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) WeakRefAttr(Attr.getLoc(), S.Context));
}
-static void HandleAliasAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
if (Attr.getNumArgs() != 1) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
@@ -735,55 +750,52 @@ static void HandleAliasAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// FIXME: check if target symbol exists in current file
- d->addAttr(::new (S.Context) AliasAttr(Attr.getLoc(), S.Context,
+ D->addAttr(::new (S.Context) AliasAttr(Attr.getLoc(), S.Context,
Str->getString()));
}
-static void HandleNakedAttr(Decl *d, const AttributeList &Attr,
- Sema &S) {
+static void handleNakedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// Check the attribute arguments.
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ if (!checkAttributeNumArgs(S, Attr, 0))
return;
- }
- if (!isa<FunctionDecl>(d)) {
+ if (!isa<FunctionDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
return;
}
- d->addAttr(::new (S.Context) NakedAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) NakedAttr(Attr.getLoc(), S.Context));
}
-static void HandleAlwaysInlineAttr(Decl *d, const AttributeList &Attr,
- Sema &S) {
+static void handleAlwaysInlineAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
// Check the attribute arguments.
if (Attr.hasParameterOrArguments()) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
- if (!isa<FunctionDecl>(d)) {
+ if (!isa<FunctionDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
return;
}
- d->addAttr(::new (S.Context) AlwaysInlineAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) AlwaysInlineAttr(Attr.getLoc(), S.Context));
}
-static void HandleMallocAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleMallocAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// Check the attribute arguments.
if (Attr.hasParameterOrArguments()) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(d)) {
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
QualType RetTy = FD->getResultType();
if (RetTy->isAnyPointerType() || RetTy->isBlockPointerType()) {
- d->addAttr(::new (S.Context) MallocAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) MallocAttr(Attr.getLoc(), S.Context));
return;
}
}
@@ -791,46 +803,44 @@ static void HandleMallocAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::warn_attribute_malloc_pointer_only);
}
-static void HandleMayAliasAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleMayAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ if (!checkAttributeNumArgs(S, Attr, 0))
return;
- }
- d->addAttr(::new (S.Context) MayAliasAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) MayAliasAttr(Attr.getLoc(), S.Context));
}
-static void HandleNoCommonAttr(Decl *d, const AttributeList &Attr, Sema &S) {
- assert(Attr.isInvalid() == false);
- if (isa<VarDecl>(d))
- d->addAttr(::new (S.Context) NoCommonAttr(Attr.getLoc(), S.Context));
+static void handleNoCommonAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ assert(!Attr.isInvalid());
+ if (isa<VarDecl>(D))
+ D->addAttr(::new (S.Context) NoCommonAttr(Attr.getLoc(), S.Context));
else
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedVariable;
}
-static void HandleCommonAttr(Decl *d, const AttributeList &Attr, Sema &S) {
- assert(Attr.isInvalid() == false);
- if (isa<VarDecl>(d))
- d->addAttr(::new (S.Context) CommonAttr(Attr.getLoc(), S.Context));
+static void handleCommonAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ assert(!Attr.isInvalid());
+ if (isa<VarDecl>(D))
+ D->addAttr(::new (S.Context) CommonAttr(Attr.getLoc(), S.Context));
else
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedVariable;
}
-static void HandleNoReturnAttr(Decl *d, const AttributeList &attr, Sema &S) {
- if (hasDeclarator(d)) return;
+static void handleNoReturnAttr(Sema &S, Decl *D, const AttributeList &attr) {
+ if (hasDeclarator(D)) return;
if (S.CheckNoReturnAttr(attr)) return;
- if (!isa<ObjCMethodDecl>(d)) {
+ if (!isa<ObjCMethodDecl>(D)) {
S.Diag(attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< attr.getName() << ExpectedFunctionOrMethod;
return;
}
- d->addAttr(::new (S.Context) NoReturnAttr(attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) NoReturnAttr(attr.getLoc(), S.Context));
}
bool Sema::CheckNoReturnAttr(const AttributeList &attr) {
@@ -843,19 +853,17 @@ bool Sema::CheckNoReturnAttr(const AttributeList &attr) {
return false;
}
-static void HandleAnalyzerNoReturnAttr(Decl *d, const AttributeList &Attr,
- Sema &S) {
+static void handleAnalyzerNoReturnAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
// The checking path for 'noreturn' and 'analyzer_noreturn' are different
// because 'analyzer_noreturn' does not impact the type.
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
- return;
- }
+ if(!checkAttributeNumArgs(S, Attr, 0))
+ return;
- if (!isFunctionOrMethod(d) && !isa<BlockDecl>(d)) {
- ValueDecl *VD = dyn_cast<ValueDecl>(d);
+ if (!isFunctionOrMethod(D) && !isa<BlockDecl>(D)) {
+ ValueDecl *VD = dyn_cast<ValueDecl>(D);
if (VD == 0 || (!VD->getType()->isBlockPointerType()
&& !VD->getType()->isFunctionPointerType())) {
S.Diag(Attr.getLoc(),
@@ -866,12 +874,11 @@ static void HandleAnalyzerNoReturnAttr(Decl *d, const AttributeList &Attr,
}
}
- d->addAttr(::new (S.Context) AnalyzerNoReturnAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) AnalyzerNoReturnAttr(Attr.getLoc(), S.Context));
}
// PS3 PPU-specific.
-static void HandleVecReturnAttr(Decl *d, const AttributeList &Attr,
- Sema &S) {
+static void handleVecReturnAttr(Sema &S, Decl *D, const AttributeList &Attr) {
/*
Returning a Vector Class in Registers
@@ -895,18 +902,18 @@ static void HandleVecReturnAttr(Decl *d, const AttributeList &Attr,
return result; // This will be returned in a register
}
*/
- if (!isa<RecordDecl>(d)) {
+ if (!isa<RecordDecl>(D)) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedClass;
return;
}
- if (d->getAttr<VecReturnAttr>()) {
+ if (D->getAttr<VecReturnAttr>()) {
S.Diag(Attr.getLoc(), diag::err_repeat_attribute) << "vecreturn";
return;
}
- RecordDecl *record = cast<RecordDecl>(d);
+ RecordDecl *record = cast<RecordDecl>(D);
int count = 0;
if (!isa<CXXRecordDecl>(record)) {
@@ -928,11 +935,11 @@ static void HandleVecReturnAttr(Decl *d, const AttributeList &Attr,
count++;
}
- d->addAttr(::new (S.Context) VecReturnAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) VecReturnAttr(Attr.getLoc(), S.Context));
}
-static void HandleDependencyAttr(Decl *d, const AttributeList &Attr, Sema &S) {
- if (!isFunctionOrMethod(d) && !isa<ParmVarDecl>(d)) {
+static void handleDependencyAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (!isFunctionOrMethod(D) && !isa<ParmVarDecl>(D)) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunctionMethodOrParameter;
return;
@@ -940,45 +947,45 @@ static void HandleDependencyAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// FIXME: Actually store the attribute on the declaration
}
-static void HandleUnusedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleUnusedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
if (Attr.hasParameterOrArguments()) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
- if (!isa<VarDecl>(d) && !isa<ObjCIvarDecl>(d) && !isFunctionOrMethod(d) &&
- !isa<TypeDecl>(d) && !isa<LabelDecl>(d)) {
+ if (!isa<VarDecl>(D) && !isa<ObjCIvarDecl>(D) && !isFunctionOrMethod(D) &&
+ !isa<TypeDecl>(D) && !isa<LabelDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedVariableFunctionOrLabel;
return;
}
- d->addAttr(::new (S.Context) UnusedAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) UnusedAttr(Attr.getLoc(), S.Context));
}
-static void HandleUsedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleUsedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
if (Attr.hasParameterOrArguments()) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
- if (const VarDecl *VD = dyn_cast<VarDecl>(d)) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
if (VD->hasLocalStorage() || VD->hasExternalStorage()) {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "used";
return;
}
- } else if (!isFunctionOrMethod(d)) {
+ } else if (!isFunctionOrMethod(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedVariableOrFunction;
return;
}
- d->addAttr(::new (S.Context) UsedAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) UsedAttr(Attr.getLoc(), S.Context));
}
-static void HandleConstructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleConstructorAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
if (Attr.getNumArgs() > 1) {
S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 1;
@@ -998,17 +1005,17 @@ static void HandleConstructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
priority = Idx.getZExtValue();
}
- if (!isa<FunctionDecl>(d)) {
+ if (!isa<FunctionDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
return;
}
- d->addAttr(::new (S.Context) ConstructorAttr(Attr.getLoc(), S.Context,
+ D->addAttr(::new (S.Context) ConstructorAttr(Attr.getLoc(), S.Context,
priority));
}
-static void HandleDestructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleDestructorAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
if (Attr.getNumArgs() > 1) {
S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 1;
@@ -1028,17 +1035,17 @@ static void HandleDestructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
priority = Idx.getZExtValue();
}
- if (!isa<FunctionDecl>(d)) {
+ if (!isa<FunctionDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
return;
}
- d->addAttr(::new (S.Context) DestructorAttr(Attr.getLoc(), S.Context,
+ D->addAttr(::new (S.Context) DestructorAttr(Attr.getLoc(), S.Context,
priority));
}
-static void HandleDeprecatedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleDeprecatedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
unsigned NumArgs = Attr.getNumArgs();
if (NumArgs > 1) {
S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 1;
@@ -1057,10 +1064,10 @@ static void HandleDeprecatedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
Str = SE->getString();
}
- d->addAttr(::new (S.Context) DeprecatedAttr(Attr.getLoc(), S.Context, Str));
+ D->addAttr(::new (S.Context) DeprecatedAttr(Attr.getLoc(), S.Context, Str));
}
-static void HandleUnavailableAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleUnavailableAttr(Sema &S, Decl *D, const AttributeList &Attr) {
unsigned NumArgs = Attr.getNumArgs();
if (NumArgs > 1) {
S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 1;
@@ -1078,11 +1085,23 @@ static void HandleUnavailableAttr(Decl *d, const AttributeList &Attr, Sema &S) {
}
Str = SE->getString();
}
- d->addAttr(::new (S.Context) UnavailableAttr(Attr.getLoc(), S.Context, Str));
+ D->addAttr(::new (S.Context) UnavailableAttr(Attr.getLoc(), S.Context, Str));
+}
+
+static void handleArcWeakrefUnavailableAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ unsigned NumArgs = Attr.getNumArgs();
+ if (NumArgs > 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 0;
+ return;
+ }
+
+ D->addAttr(::new (S.Context) ArcWeakrefUnavailableAttr(
+ Attr.getLoc(), S.Context));
}
-static void HandleAvailabilityAttr(Decl *d, const AttributeList &Attr,
- Sema &S) {
+static void handleAvailabilityAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
IdentifierInfo *Platform = Attr.getParameterName();
SourceLocation PlatformLoc = Attr.getParameterLoc();
@@ -1126,7 +1145,7 @@ static void HandleAvailabilityAttr(Decl *d, const AttributeList &Attr,
return;
}
- d->addAttr(::new (S.Context) AvailabilityAttr(Attr.getLoc(), S.Context,
+ D->addAttr(::new (S.Context) AvailabilityAttr(Attr.getLoc(), S.Context,
Platform,
Introduced.Version,
Deprecated.Version,
@@ -1134,12 +1153,10 @@ static void HandleAvailabilityAttr(Decl *d, const AttributeList &Attr,
IsUnavailable));
}
-static void HandleVisibilityAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
- if (Attr.getNumArgs() != 1) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ if(!checkAttributeNumArgs(S, Attr, 1))
return;
- }
Expr *Arg = Attr.getArg(0);
Arg = Arg->IgnoreParenCasts();
@@ -1167,30 +1184,30 @@ static void HandleVisibilityAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
- d->addAttr(::new (S.Context) VisibilityAttr(Attr.getLoc(), S.Context, type));
+ D->addAttr(::new (S.Context) VisibilityAttr(Attr.getLoc(), S.Context, type));
}
-static void HandleObjCMethodFamilyAttr(Decl *decl, const AttributeList &attr,
- Sema &S) {
+static void handleObjCMethodFamilyAttr(Sema &S, Decl *decl,
+ const AttributeList &Attr) {
ObjCMethodDecl *method = dyn_cast<ObjCMethodDecl>(decl);
if (!method) {
- S.Diag(attr.getLoc(), diag::err_attribute_wrong_decl_type)
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
<< ExpectedMethod;
return;
}
- if (attr.getNumArgs() != 0 || !attr.getParameterName()) {
- if (!attr.getParameterName() && attr.getNumArgs() == 1) {
- S.Diag(attr.getLoc(), diag::err_attribute_argument_n_not_string)
+ if (Attr.getNumArgs() != 0 || !Attr.getParameterName()) {
+ if (!Attr.getParameterName() && Attr.getNumArgs() == 1) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
<< "objc_method_family" << 1;
} else {
- S.Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
}
- attr.setInvalid();
+ Attr.setInvalid();
return;
}
- llvm::StringRef param = attr.getParameterName()->getName();
+ llvm::StringRef param = Attr.getParameterName()->getName();
ObjCMethodFamilyAttr::FamilyKind family;
if (param == "none")
family = ObjCMethodFamilyAttr::OMF_None;
@@ -1207,20 +1224,26 @@ static void HandleObjCMethodFamilyAttr(Decl *decl, const AttributeList &attr,
else {
// Just warn and ignore it. This is future-proof against new
// families being used in system headers.
- S.Diag(attr.getParameterLoc(), diag::warn_unknown_method_family);
+ S.Diag(Attr.getParameterLoc(), diag::warn_unknown_method_family);
return;
}
- decl->addAttr(new (S.Context) ObjCMethodFamilyAttr(attr.getLoc(),
- S.Context, family));
+ if (family == ObjCMethodFamilyAttr::OMF_init &&
+ !method->getResultType()->isObjCObjectPointerType()) {
+ S.Diag(method->getLocation(), diag::err_init_method_bad_return_type)
+ << method->getResultType();
+ // Ignore the attribute.
+ return;
+ }
+
+ method->addAttr(new (S.Context) ObjCMethodFamilyAttr(Attr.getLoc(),
+ S.Context, family));
}
-static void HandleObjCExceptionAttr(Decl *D, const AttributeList &Attr,
- Sema &S) {
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+static void handleObjCExceptionAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ if (!checkAttributeNumArgs(S, Attr, 0))
return;
- }
ObjCInterfaceDecl *OCI = dyn_cast<ObjCInterfaceDecl>(D);
if (OCI == 0) {
@@ -1231,7 +1254,7 @@ static void HandleObjCExceptionAttr(Decl *D, const AttributeList &Attr,
D->addAttr(::new (S.Context) ObjCExceptionAttr(Attr.getLoc(), S.Context));
}
-static void HandleObjCNSObject(Decl *D, const AttributeList &Attr, Sema &S) {
+static void handleObjCNSObject(Sema &S, Decl *D, const AttributeList &Attr) {
if (Attr.getNumArgs() != 0) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
return;
@@ -1248,7 +1271,7 @@ static void HandleObjCNSObject(Decl *D, const AttributeList &Attr, Sema &S) {
}
static void
-HandleOverloadableAttr(Decl *D, const AttributeList &Attr, Sema &S) {
+handleOverloadableAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (Attr.getNumArgs() != 0) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
return;
@@ -1262,7 +1285,7 @@ HandleOverloadableAttr(Decl *D, const AttributeList &Attr, Sema &S) {
D->addAttr(::new (S.Context) OverloadableAttr(Attr.getLoc(), S.Context));
}
-static void HandleBlocksAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleBlocksAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (!Attr.getParameterName()) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
<< "blocks" << 1;
@@ -1283,10 +1306,10 @@ static void HandleBlocksAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
- d->addAttr(::new (S.Context) BlocksAttr(Attr.getLoc(), S.Context, type));
+ D->addAttr(::new (S.Context) BlocksAttr(Attr.getLoc(), S.Context, type));
}
-static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
if (Attr.getNumArgs() > 2) {
S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 2;
@@ -1333,7 +1356,7 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) {
}
}
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(d)) {
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
const FunctionType *FT = FD->getType()->getAs<FunctionType>();
assert(FT && "FunctionDecl has non-function type?");
@@ -1346,19 +1369,19 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 0;
return;
}
- } else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(d)) {
+ } else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
if (!MD->isVariadic()) {
S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 0;
return;
}
- } else if (isa<BlockDecl>(d)) {
+ } else if (isa<BlockDecl>(D)) {
// Note! BlockDecl is typeless. Variadic diagnostics will be issued by the
// caller.
;
- } else if (const VarDecl *V = dyn_cast<VarDecl>(d)) {
+ } else if (const VarDecl *V = dyn_cast<VarDecl>(D)) {
QualType Ty = V->getType();
if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()) {
- const FunctionType *FT = Ty->isFunctionPointerType() ? getFunctionType(d)
+ const FunctionType *FT = Ty->isFunctionPointerType() ? getFunctionType(D)
: Ty->getAs<BlockPointerType>()->getPointeeType()->getAs<FunctionType>();
if (!cast<FunctionProtoType>(FT)->isVariadic()) {
int m = Ty->isFunctionPointerType() ? 0 : 1;
@@ -1375,16 +1398,14 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) {
<< Attr.getName() << ExpectedFunctionMethodOrBlock;
return;
}
- d->addAttr(::new (S.Context) SentinelAttr(Attr.getLoc(), S.Context, sentinel,
+ D->addAttr(::new (S.Context) SentinelAttr(Attr.getLoc(), S.Context, sentinel,
nullPos));
}
-static void HandleWarnUnusedResult(Decl *D, const AttributeList &Attr, Sema &S) {
+static void handleWarnUnusedResult(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ if (!checkAttributeNumArgs(S, Attr, 0))
return;
- }
if (!isFunction(D) && !isa<ObjCMethodDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
@@ -1407,36 +1428,35 @@ static void HandleWarnUnusedResult(Decl *D, const AttributeList &Attr, Sema &S)
D->addAttr(::new (S.Context) WarnUnusedResultAttr(Attr.getLoc(), S.Context));
}
-static void HandleWeakAttr(Decl *d, const AttributeList &attr, Sema &S) {
+static void handleWeakAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
- if (attr.hasParameterOrArguments()) {
- S.Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ if (Attr.hasParameterOrArguments()) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
- if (!isa<VarDecl>(d) && !isa<FunctionDecl>(d)) {
- S.Diag(attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << attr.getName() << ExpectedVariableOrFunction;
+ if (!isa<VarDecl>(D) && !isa<FunctionDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedVariableOrFunction;
return;
}
- NamedDecl *nd = cast<NamedDecl>(d);
+ NamedDecl *nd = cast<NamedDecl>(D);
// 'weak' only applies to declarations with external linkage.
if (hasEffectivelyInternalLinkage(nd)) {
- S.Diag(attr.getLoc(), diag::err_attribute_weak_static);
+ S.Diag(Attr.getLoc(), diag::err_attribute_weak_static);
return;
}
- nd->addAttr(::new (S.Context) WeakAttr(attr.getLoc(), S.Context));
+ nd->addAttr(::new (S.Context) WeakAttr(Attr.getLoc(), S.Context));
}
-static void HandleWeakImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
+static void handleWeakImportAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ if (!checkAttributeNumArgs(S, Attr, 0))
return;
- }
+
// weak_import only applies to variable & function declarations.
bool isDef = false;
@@ -1459,13 +1479,11 @@ static void HandleWeakImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
D->addAttr(::new (S.Context) WeakImportAttr(Attr.getLoc(), S.Context));
}
-static void HandleReqdWorkGroupSize(Decl *D, const AttributeList &Attr,
- Sema &S) {
+static void handleReqdWorkGroupSize(Sema &S, Decl *D,
+ const AttributeList &Attr) {
// Attribute has 3 arguments.
- if (Attr.getNumArgs() != 3) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ if (!checkAttributeNumArgs(S, Attr, 3))
return;
- }
unsigned WGSize[3];
for (unsigned i = 0; i < 3; ++i) {
@@ -1484,12 +1502,10 @@ static void HandleReqdWorkGroupSize(Decl *D, const AttributeList &Attr,
WGSize[2]));
}
-static void HandleSectionAttr(Decl *D, const AttributeList &Attr, Sema &S) {
+static void handleSectionAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// Attribute has no arguments.
- if (Attr.getNumArgs() != 1) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ if (!checkAttributeNumArgs(S, Attr, 1))
return;
- }
// Make sure that there is a string literal as the sections's single
// argument.
@@ -1519,37 +1535,45 @@ static void HandleSectionAttr(Decl *D, const AttributeList &Attr, Sema &S) {
}
-static void HandleNothrowAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleNothrowAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
if (Attr.hasParameterOrArguments()) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
-
- d->addAttr(::new (S.Context) NoThrowAttr(Attr.getLoc(), S.Context));
+
+ if (NoThrowAttr *Existing = D->getAttr<NoThrowAttr>()) {
+ if (Existing->getLocation().isInvalid())
+ Existing->setLocation(Attr.getLoc());
+ } else {
+ D->addAttr(::new (S.Context) NoThrowAttr(Attr.getLoc(), S.Context));
+ }
}
-static void HandleConstAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleConstAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
if (Attr.hasParameterOrArguments()) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
- d->addAttr(::new (S.Context) ConstAttr(Attr.getLoc(), S.Context));
+ if (ConstAttr *Existing = D->getAttr<ConstAttr>()) {
+ if (Existing->getLocation().isInvalid())
+ Existing->setLocation(Attr.getLoc());
+ } else {
+ D->addAttr(::new (S.Context) ConstAttr(Attr.getLoc(), S.Context));
+ }
}
-static void HandlePureAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handlePureAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ if (!checkAttributeNumArgs(S, Attr, 0))
return;
- }
- d->addAttr(::new (S.Context) PureAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) PureAttr(Attr.getLoc(), S.Context));
}
-static void HandleCleanupAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (!Attr.getParameterName()) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
return;
@@ -1560,7 +1584,7 @@ static void HandleCleanupAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
- VarDecl *VD = dyn_cast<VarDecl>(d);
+ VarDecl *VD = dyn_cast<VarDecl>(D);
if (!VD || !VD->hasLocalStorage()) {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "cleanup";
@@ -1605,18 +1629,17 @@ static void HandleCleanupAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
- d->addAttr(::new (S.Context) CleanupAttr(Attr.getLoc(), S.Context, FD));
+ D->addAttr(::new (S.Context) CleanupAttr(Attr.getLoc(), S.Context, FD));
S.MarkDeclarationReferenced(Attr.getParameterLoc(), FD);
}
/// Handle __attribute__((format_arg((idx)))) attribute based on
/// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
-static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) {
- if (Attr.getNumArgs() != 1) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+static void handleFormatArgAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (!checkAttributeNumArgs(S, Attr, 1))
return;
- }
- if (!isFunctionOrMethod(d) || !hasFunctionProto(d)) {
+
+ if (!isFunctionOrMethod(D) || !hasFunctionProto(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
return;
@@ -1624,8 +1647,8 @@ static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// In C++ the implicit 'this' function parameter also counts, and they are
// counted from one.
- bool HasImplicitThisParam = isInstanceMethod(d);
- unsigned NumArgs = getFunctionOrMethodNumArgs(d) + HasImplicitThisParam;
+ bool HasImplicitThisParam = isInstanceMethod(D);
+ unsigned NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam;
unsigned FirstIdx = 1;
// checks for the 2nd argument
@@ -1656,7 +1679,7 @@ static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) {
}
// make sure the format string is really a string
- QualType Ty = getFunctionOrMethodArgType(d, ArgIdx);
+ QualType Ty = getFunctionOrMethodArgType(D, ArgIdx);
bool not_nsstring_type = !isNSStringType(Ty, S.Context);
if (not_nsstring_type &&
@@ -1669,7 +1692,7 @@ static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) {
<< IdxExpr->getSourceRange();
return;
}
- Ty = getFunctionOrMethodResultType(d);
+ Ty = getFunctionOrMethodResultType(D);
if (!isNSStringType(Ty, S.Context) &&
!isCFStringType(Ty, S.Context) &&
(!Ty->isPointerType() ||
@@ -1681,7 +1704,7 @@ static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
- d->addAttr(::new (S.Context) FormatArgAttr(Attr.getLoc(), S.Context,
+ D->addAttr(::new (S.Context) FormatArgAttr(Attr.getLoc(), S.Context,
Idx.getZExtValue()));
}
@@ -1722,19 +1745,19 @@ static FormatAttrKind getFormatAttrKind(llvm::StringRef Format) {
/// Handle __attribute__((init_priority(priority))) attributes based on
/// http://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Attributes.html
-static void HandleInitPriorityAttr(Decl *d, const AttributeList &Attr,
- Sema &S) {
+static void handleInitPriorityAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
if (!S.getLangOptions().CPlusPlus) {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
return;
}
- if (!isa<VarDecl>(d) || S.getCurFunctionOrMethodDecl()) {
+ if (!isa<VarDecl>(D) || S.getCurFunctionOrMethodDecl()) {
S.Diag(Attr.getLoc(), diag::err_init_priority_object_attr);
Attr.setInvalid();
return;
}
- QualType T = dyn_cast<VarDecl>(d)->getType();
+ QualType T = dyn_cast<VarDecl>(D)->getType();
if (S.Context.getAsArrayType(T))
T = S.Context.getBaseElementType(T);
if (!T->getAs<RecordType>()) {
@@ -1765,13 +1788,13 @@ static void HandleInitPriorityAttr(Decl *d, const AttributeList &Attr,
Attr.setInvalid();
return;
}
- d->addAttr(::new (S.Context) InitPriorityAttr(Attr.getLoc(), S.Context,
+ D->addAttr(::new (S.Context) InitPriorityAttr(Attr.getLoc(), S.Context,
prioritynum));
}
/// Handle __attribute__((format(type,idx,firstarg))) attributes based on
/// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
-static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (!Attr.getParameterName()) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
@@ -1784,7 +1807,7 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
- if (!isFunctionOrMethodOrBlock(d) || !hasFunctionProto(d)) {
+ if (!isFunctionOrMethodOrBlock(D) || !hasFunctionProto(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
return;
@@ -1792,8 +1815,8 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// In C++ the implicit 'this' function parameter also counts, and they are
// counted from one.
- bool HasImplicitThisParam = isInstanceMethod(d);
- unsigned NumArgs = getFunctionOrMethodNumArgs(d) + HasImplicitThisParam;
+ bool HasImplicitThisParam = isInstanceMethod(D);
+ unsigned NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam;
unsigned FirstIdx = 1;
llvm::StringRef Format = Attr.getParameterName()->getName();
@@ -1844,7 +1867,7 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
}
// make sure the format string is really a string
- QualType Ty = getFunctionOrMethodArgType(d, ArgIdx);
+ QualType Ty = getFunctionOrMethodArgType(D, ArgIdx);
if (Kind == CFStringFormat) {
if (!isCFStringType(Ty, S.Context)) {
@@ -1881,10 +1904,10 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// check if the function is variadic if the 3rd argument non-zero
if (FirstArg != 0) {
- if (isFunctionOrMethodVariadic(d)) {
+ if (isFunctionOrMethodVariadic(D)) {
++NumArgs; // +1 for ...
} else {
- S.Diag(d->getLocation(), diag::err_format_attribute_requires_variadic);
+ S.Diag(D->getLocation(), diag::err_format_attribute_requires_variadic);
return;
}
}
@@ -1904,26 +1927,42 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
- d->addAttr(::new (S.Context) FormatAttr(Attr.getLoc(), S.Context, Format,
+ // Check whether we already have an equivalent format attribute.
+ for (specific_attr_iterator<FormatAttr>
+ i = D->specific_attr_begin<FormatAttr>(),
+ e = D->specific_attr_end<FormatAttr>();
+ i != e ; ++i) {
+ FormatAttr *f = *i;
+ if (f->getType() == Format &&
+ f->getFormatIdx() == (int)Idx.getZExtValue() &&
+ f->getFirstArg() == (int)FirstArg.getZExtValue()) {
+ // If we don't have a valid location for this attribute, adopt the
+ // location.
+ if (f->getLocation().isInvalid())
+ f->setLocation(Attr.getLoc());
+ return;
+ }
+ }
+
+ D->addAttr(::new (S.Context) FormatAttr(Attr.getLoc(), S.Context, Format,
Idx.getZExtValue(),
FirstArg.getZExtValue()));
}
-static void HandleTransparentUnionAttr(Decl *d, const AttributeList &Attr,
- Sema &S) {
+static void handleTransparentUnionAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
// check the attribute arguments.
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ if (!checkAttributeNumArgs(S, Attr, 0))
return;
- }
+
// Try to find the underlying union declaration.
RecordDecl *RD = 0;
- TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(d);
+ TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D);
if (TD && TD->getUnderlyingType()->isUnionType())
RD = TD->getUnderlyingType()->getAsUnionType()->getDecl();
else
- RD = dyn_cast<RecordDecl>(d);
+ RD = dyn_cast<RecordDecl>(D);
if (!RD || !RD->isUnion()) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
@@ -1977,12 +2016,11 @@ static void HandleTransparentUnionAttr(Decl *d, const AttributeList &Attr,
RD->addAttr(::new (S.Context) TransparentUnionAttr(Attr.getLoc(), S.Context));
}
-static void HandleAnnotateAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleAnnotateAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
- if (Attr.getNumArgs() != 1) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ if (!checkAttributeNumArgs(S, Attr, 1))
return;
- }
+
Expr *ArgExpr = Attr.getArg(0);
StringLiteral *SE = dyn_cast<StringLiteral>(ArgExpr);
@@ -1992,11 +2030,11 @@ static void HandleAnnotateAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(ArgExpr->getLocStart(), diag::err_attribute_not_string) <<"annotate";
return;
}
- d->addAttr(::new (S.Context) AnnotateAttr(Attr.getLoc(), S.Context,
+ D->addAttr(::new (S.Context) AnnotateAttr(Attr.getLoc(), S.Context,
SE->getString()));
}
-static void HandleAlignedAttr(Decl *D, const AttributeList &Attr, Sema &S) {
+static void handleAlignedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
if (Attr.getNumArgs() > 1) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
@@ -2045,21 +2083,20 @@ void Sema::AddAlignedAttr(SourceLocation AttrLoc, Decl *D, TypeSourceInfo *TS) {
return;
}
-/// HandleModeAttr - This attribute modifies the width of a decl with primitive
+/// handleModeAttr - This attribute modifies the width of a decl with primitive
/// type.
///
/// Despite what would be logical, the mode attribute is a decl attribute, not a
/// type attribute: 'int ** __attribute((mode(HI))) *G;' tries to make 'G' be
/// HImode, not an intermediate pointer.
-static void HandleModeAttr(Decl *D, const AttributeList &Attr, Sema &S) {
+static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// This attribute isn't documented, but glibc uses it. It changes
// the width of an int or unsigned int to the specified size.
// Check that there aren't any arguments
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ if (!checkAttributeNumArgs(S, Attr, 0))
return;
- }
+
IdentifierInfo *Name = Attr.getParameterName();
if (!Name) {
@@ -2216,57 +2253,53 @@ static void HandleModeAttr(Decl *D, const AttributeList &Attr, Sema &S) {
cast<ValueDecl>(D)->setType(NewTy);
}
-static void HandleNoDebugAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleNoDebugAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
- if (Attr.getNumArgs() > 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ if (!checkAttributeNumArgs(S, Attr, 0))
return;
- }
- if (!isFunctionOrMethod(d)) {
+ if (!isFunctionOrMethod(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
return;
}
- d->addAttr(::new (S.Context) NoDebugAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) NoDebugAttr(Attr.getLoc(), S.Context));
}
-static void HandleNoInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleNoInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ if (!checkAttributeNumArgs(S, Attr, 0))
return;
- }
- if (!isa<FunctionDecl>(d)) {
+
+ if (!isa<FunctionDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
return;
}
- d->addAttr(::new (S.Context) NoInlineAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) NoInlineAttr(Attr.getLoc(), S.Context));
}
-static void HandleNoInstrumentFunctionAttr(Decl *d, const AttributeList &Attr,
- Sema &S) {
+static void handleNoInstrumentFunctionAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
// check the attribute arguments.
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ if (!checkAttributeNumArgs(S, Attr, 0))
return;
- }
- if (!isa<FunctionDecl>(d)) {
+
+ if (!isa<FunctionDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
return;
}
- d->addAttr(::new (S.Context) NoInstrumentFunctionAttr(Attr.getLoc(),
+ D->addAttr(::new (S.Context) NoInstrumentFunctionAttr(Attr.getLoc(),
S.Context));
}
-static void HandleConstantAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleConstantAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (S.LangOpts.CUDA) {
// check the attribute arguments.
if (Attr.hasParameterOrArguments()) {
@@ -2274,19 +2307,19 @@ static void HandleConstantAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
- if (!isa<VarDecl>(d)) {
+ if (!isa<VarDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedVariable;
return;
}
- d->addAttr(::new (S.Context) CUDAConstantAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) CUDAConstantAttr(Attr.getLoc(), S.Context));
} else {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "constant";
}
}
-static void HandleDeviceAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleDeviceAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (S.LangOpts.CUDA) {
// check the attribute arguments.
if (Attr.getNumArgs() != 0) {
@@ -2294,33 +2327,31 @@ static void HandleDeviceAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
- if (!isa<FunctionDecl>(d) && !isa<VarDecl>(d)) {
+ if (!isa<FunctionDecl>(D) && !isa<VarDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedVariableOrFunction;
return;
}
- d->addAttr(::new (S.Context) CUDADeviceAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) CUDADeviceAttr(Attr.getLoc(), S.Context));
} else {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "device";
}
}
-static void HandleGlobalAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleGlobalAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (S.LangOpts.CUDA) {
// check the attribute arguments.
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ if (!checkAttributeNumArgs(S, Attr, 0))
return;
- }
- if (!isa<FunctionDecl>(d)) {
+ if (!isa<FunctionDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
return;
}
- FunctionDecl *FD = cast<FunctionDecl>(d);
+ FunctionDecl *FD = cast<FunctionDecl>(D);
if (!FD->getResultType()->isVoidType()) {
TypeLoc TL = FD->getTypeSourceInfo()->getTypeLoc().IgnoreParens();
if (FunctionTypeLoc* FTL = dyn_cast<FunctionTypeLoc>(&TL)) {
@@ -2335,60 +2366,56 @@ static void HandleGlobalAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
- d->addAttr(::new (S.Context) CUDAGlobalAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) CUDAGlobalAttr(Attr.getLoc(), S.Context));
} else {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "global";
}
}
-static void HandleHostAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleHostAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (S.LangOpts.CUDA) {
// check the attribute arguments.
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ if (!checkAttributeNumArgs(S, Attr, 0))
return;
- }
- if (!isa<FunctionDecl>(d)) {
+
+ if (!isa<FunctionDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
return;
}
- d->addAttr(::new (S.Context) CUDAHostAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) CUDAHostAttr(Attr.getLoc(), S.Context));
} else {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "host";
}
}
-static void HandleSharedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleSharedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (S.LangOpts.CUDA) {
// check the attribute arguments.
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ if (!checkAttributeNumArgs(S, Attr, 0))
return;
- }
- if (!isa<VarDecl>(d)) {
+
+ if (!isa<VarDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedVariable;
return;
}
- d->addAttr(::new (S.Context) CUDASharedAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) CUDASharedAttr(Attr.getLoc(), S.Context));
} else {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "shared";
}
}
-static void HandleGNUInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleGNUInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ if (!checkAttributeNumArgs(S, Attr, 0))
return;
- }
- FunctionDecl *Fn = dyn_cast<FunctionDecl>(d);
+ FunctionDecl *Fn = dyn_cast<FunctionDecl>(D);
if (Fn == 0) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
@@ -2400,47 +2427,47 @@ static void HandleGNUInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
- d->addAttr(::new (S.Context) GNUInlineAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) GNUInlineAttr(Attr.getLoc(), S.Context));
}
-static void HandleCallConvAttr(Decl *d, const AttributeList &attr, Sema &S) {
- if (hasDeclarator(d)) return;
+static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (hasDeclarator(D)) return;
- // Diagnostic is emitted elsewhere: here we store the (valid) attr
+ // Diagnostic is emitted elsewhere: here we store the (valid) Attr
// in the Decl node for syntactic reasoning, e.g., pretty-printing.
CallingConv CC;
- if (S.CheckCallingConvAttr(attr, CC))
+ if (S.CheckCallingConvAttr(Attr, CC))
return;
- if (!isa<ObjCMethodDecl>(d)) {
- S.Diag(attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << attr.getName() << ExpectedFunctionOrMethod;
+ if (!isa<ObjCMethodDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedFunctionOrMethod;
return;
}
- switch (attr.getKind()) {
+ switch (Attr.getKind()) {
case AttributeList::AT_fastcall:
- d->addAttr(::new (S.Context) FastCallAttr(attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) FastCallAttr(Attr.getLoc(), S.Context));
return;
case AttributeList::AT_stdcall:
- d->addAttr(::new (S.Context) StdCallAttr(attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) StdCallAttr(Attr.getLoc(), S.Context));
return;
case AttributeList::AT_thiscall:
- d->addAttr(::new (S.Context) ThisCallAttr(attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) ThisCallAttr(Attr.getLoc(), S.Context));
return;
case AttributeList::AT_cdecl:
- d->addAttr(::new (S.Context) CDeclAttr(attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) CDeclAttr(Attr.getLoc(), S.Context));
return;
case AttributeList::AT_pascal:
- d->addAttr(::new (S.Context) PascalAttr(attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) PascalAttr(Attr.getLoc(), S.Context));
return;
case AttributeList::AT_pcs: {
- Expr *Arg = attr.getArg(0);
+ Expr *Arg = Attr.getArg(0);
StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
if (Str == 0 || Str->isWide()) {
- S.Diag(attr.getLoc(), diag::err_attribute_argument_n_not_string)
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
<< "pcs" << 1;
- attr.setInvalid();
+ Attr.setInvalid();
return;
}
@@ -2451,12 +2478,12 @@ static void HandleCallConvAttr(Decl *d, const AttributeList &attr, Sema &S) {
else if (StrRef == "aapcs-vfp")
PCS = PcsAttr::AAPCS_VFP;
else {
- S.Diag(attr.getLoc(), diag::err_invalid_pcs);
- attr.setInvalid();
+ S.Diag(Attr.getLoc(), diag::err_invalid_pcs);
+ Attr.setInvalid();
return;
}
- d->addAttr(::new (S.Context) PcsAttr(attr.getLoc(), S.Context, PCS));
+ D->addAttr(::new (S.Context) PcsAttr(Attr.getLoc(), S.Context, PCS));
}
default:
llvm_unreachable("unexpected attribute kind");
@@ -2464,9 +2491,9 @@ static void HandleCallConvAttr(Decl *d, const AttributeList &attr, Sema &S) {
}
}
-static void HandleOpenCLKernelAttr(Decl *d, const AttributeList &Attr, Sema &S){
- assert(Attr.isInvalid() == false);
- d->addAttr(::new (S.Context) OpenCLKernelAttr(Attr.getLoc(), S.Context));
+static void handleOpenCLKernelAttr(Sema &S, Decl *D, const AttributeList &Attr){
+ assert(!Attr.isInvalid());
+ D->addAttr(::new (S.Context) OpenCLKernelAttr(Attr.getLoc(), S.Context));
}
bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC) {
@@ -2515,63 +2542,63 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC) {
return false;
}
-static void HandleRegparmAttr(Decl *d, const AttributeList &attr, Sema &S) {
- if (hasDeclarator(d)) return;
+static void handleRegparmAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (hasDeclarator(D)) return;
unsigned numParams;
- if (S.CheckRegparmAttr(attr, numParams))
+ if (S.CheckRegparmAttr(Attr, numParams))
return;
- if (!isa<ObjCMethodDecl>(d)) {
- S.Diag(attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << attr.getName() << ExpectedFunctionOrMethod;
+ if (!isa<ObjCMethodDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedFunctionOrMethod;
return;
}
- d->addAttr(::new (S.Context) RegparmAttr(attr.getLoc(), S.Context, numParams));
+ D->addAttr(::new (S.Context) RegparmAttr(Attr.getLoc(), S.Context, numParams));
}
/// Checks a regparm attribute, returning true if it is ill-formed and
/// otherwise setting numParams to the appropriate value.
-bool Sema::CheckRegparmAttr(const AttributeList &attr, unsigned &numParams) {
- if (attr.isInvalid())
+bool Sema::CheckRegparmAttr(const AttributeList &Attr, unsigned &numParams) {
+ if (Attr.isInvalid())
return true;
- if (attr.getNumArgs() != 1) {
- Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
- attr.setInvalid();
+ if (Attr.getNumArgs() != 1) {
+ Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ Attr.setInvalid();
return true;
}
- Expr *NumParamsExpr = attr.getArg(0);
+ Expr *NumParamsExpr = Attr.getArg(0);
llvm::APSInt NumParams(32);
if (NumParamsExpr->isTypeDependent() || NumParamsExpr->isValueDependent() ||
!NumParamsExpr->isIntegerConstantExpr(NumParams, Context)) {
- Diag(attr.getLoc(), diag::err_attribute_argument_not_int)
+ Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
<< "regparm" << NumParamsExpr->getSourceRange();
- attr.setInvalid();
+ Attr.setInvalid();
return true;
}
if (Context.Target.getRegParmMax() == 0) {
- Diag(attr.getLoc(), diag::err_attribute_regparm_wrong_platform)
+ Diag(Attr.getLoc(), diag::err_attribute_regparm_wrong_platform)
<< NumParamsExpr->getSourceRange();
- attr.setInvalid();
+ Attr.setInvalid();
return true;
}
numParams = NumParams.getZExtValue();
if (numParams > Context.Target.getRegParmMax()) {
- Diag(attr.getLoc(), diag::err_attribute_regparm_invalid_number)
+ Diag(Attr.getLoc(), diag::err_attribute_regparm_invalid_number)
<< Context.Target.getRegParmMax() << NumParamsExpr->getSourceRange();
- attr.setInvalid();
+ Attr.setInvalid();
return true;
}
return false;
}
-static void HandleLaunchBoundsAttr(Decl *d, const AttributeList &Attr, Sema &S){
+static void handleLaunchBoundsAttr(Sema &S, Decl *D, const AttributeList &Attr){
if (S.LangOpts.CUDA) {
// check the attribute arguments.
if (Attr.getNumArgs() != 1 && Attr.getNumArgs() != 2) {
@@ -2580,7 +2607,7 @@ static void HandleLaunchBoundsAttr(Decl *d, const AttributeList &Attr, Sema &S){
return;
}
- if (!isFunctionOrMethod(d)) {
+ if (!isFunctionOrMethod(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunctionOrMethod;
return;
@@ -2608,7 +2635,7 @@ static void HandleLaunchBoundsAttr(Decl *d, const AttributeList &Attr, Sema &S){
}
}
- d->addAttr(::new (S.Context) CUDALaunchBoundsAttr(Attr.getLoc(), S.Context,
+ D->addAttr(::new (S.Context) CUDALaunchBoundsAttr(Attr.getLoc(), S.Context,
MaxThreads.getZExtValue(),
MinBlocks.getZExtValue()));
} else {
@@ -2627,16 +2654,16 @@ static bool isValidSubjectOfCFAttribute(Sema &S, QualType type) {
return type->isPointerType() || isValidSubjectOfNSAttribute(S, type);
}
-static void HandleNSConsumedAttr(Decl *d, const AttributeList &attr, Sema &S) {
- ParmVarDecl *param = dyn_cast<ParmVarDecl>(d);
+static void handleNSConsumedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ ParmVarDecl *param = dyn_cast<ParmVarDecl>(D);
if (!param) {
- S.Diag(d->getLocStart(), diag::warn_attribute_wrong_decl_type)
- << SourceRange(attr.getLoc()) << attr.getName() << ExpectedParameter;
+ S.Diag(D->getLocStart(), diag::warn_attribute_wrong_decl_type)
+ << SourceRange(Attr.getLoc()) << Attr.getName() << ExpectedParameter;
return;
}
bool typeOK, cf;
- if (attr.getKind() == AttributeList::AT_ns_consumed) {
+ if (Attr.getKind() == AttributeList::AT_ns_consumed) {
typeOK = isValidSubjectOfNSAttribute(S, param->getType());
cf = false;
} else {
@@ -2645,47 +2672,52 @@ static void HandleNSConsumedAttr(Decl *d, const AttributeList &attr, Sema &S) {
}
if (!typeOK) {
- S.Diag(d->getLocStart(), diag::warn_ns_attribute_wrong_parameter_type)
- << SourceRange(attr.getLoc()) << attr.getName() << cf;
+ S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_parameter_type)
+ << SourceRange(Attr.getLoc()) << Attr.getName() << cf;
return;
}
if (cf)
- param->addAttr(::new (S.Context) CFConsumedAttr(attr.getLoc(), S.Context));
+ param->addAttr(::new (S.Context) CFConsumedAttr(Attr.getLoc(), S.Context));
else
- param->addAttr(::new (S.Context) NSConsumedAttr(attr.getLoc(), S.Context));
+ param->addAttr(::new (S.Context) NSConsumedAttr(Attr.getLoc(), S.Context));
}
-static void HandleNSConsumesSelfAttr(Decl *d, const AttributeList &attr,
- Sema &S) {
- if (!isa<ObjCMethodDecl>(d)) {
- S.Diag(d->getLocStart(), diag::warn_attribute_wrong_decl_type)
- << SourceRange(attr.getLoc()) << attr.getName() << ExpectedMethod;
+static void handleNSConsumesSelfAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ if (!isa<ObjCMethodDecl>(D)) {
+ S.Diag(D->getLocStart(), diag::warn_attribute_wrong_decl_type)
+ << SourceRange(Attr.getLoc()) << Attr.getName() << ExpectedMethod;
return;
}
- d->addAttr(::new (S.Context) NSConsumesSelfAttr(attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) NSConsumesSelfAttr(Attr.getLoc(), S.Context));
}
-static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &attr,
- Sema &S) {
+static void handleNSReturnsRetainedAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
QualType returnType;
- if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(d))
+ if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
returnType = MD->getResultType();
- else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(d))
+ else if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D))
+ returnType = PD->getType();
+ else if (S.getLangOptions().ObjCAutoRefCount && hasDeclarator(D) &&
+ (Attr.getKind() == AttributeList::AT_ns_returns_retained))
+ return; // ignore: was handled as a type attribute
+ else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
returnType = FD->getResultType();
else {
- S.Diag(d->getLocStart(), diag::warn_attribute_wrong_decl_type)
- << SourceRange(attr.getLoc()) << attr.getName()
+ S.Diag(D->getLocStart(), diag::warn_attribute_wrong_decl_type)
+ << SourceRange(Attr.getLoc()) << Attr.getName()
<< ExpectedFunctionOrMethod;
return;
}
bool typeOK;
bool cf;
- switch (attr.getKind()) {
+ switch (Attr.getKind()) {
default: llvm_unreachable("invalid ownership attribute"); return;
case AttributeList::AT_ns_returns_autoreleased:
case AttributeList::AT_ns_returns_retained:
@@ -2702,39 +2734,95 @@ static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &attr,
}
if (!typeOK) {
- S.Diag(d->getLocStart(), diag::warn_ns_attribute_wrong_return_type)
- << SourceRange(attr.getLoc())
- << attr.getName() << isa<ObjCMethodDecl>(d) << cf;
+ S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_return_type)
+ << SourceRange(Attr.getLoc())
+ << Attr.getName() << isa<ObjCMethodDecl>(D) << cf;
return;
}
- switch (attr.getKind()) {
+ switch (Attr.getKind()) {
default:
assert(0 && "invalid ownership attribute");
return;
case AttributeList::AT_ns_returns_autoreleased:
- d->addAttr(::new (S.Context) NSReturnsAutoreleasedAttr(attr.getLoc(),
+ D->addAttr(::new (S.Context) NSReturnsAutoreleasedAttr(Attr.getLoc(),
S.Context));
return;
case AttributeList::AT_cf_returns_not_retained:
- d->addAttr(::new (S.Context) CFReturnsNotRetainedAttr(attr.getLoc(),
+ D->addAttr(::new (S.Context) CFReturnsNotRetainedAttr(Attr.getLoc(),
S.Context));
return;
case AttributeList::AT_ns_returns_not_retained:
- d->addAttr(::new (S.Context) NSReturnsNotRetainedAttr(attr.getLoc(),
+ D->addAttr(::new (S.Context) NSReturnsNotRetainedAttr(Attr.getLoc(),
S.Context));
return;
case AttributeList::AT_cf_returns_retained:
- d->addAttr(::new (S.Context) CFReturnsRetainedAttr(attr.getLoc(),
+ D->addAttr(::new (S.Context) CFReturnsRetainedAttr(Attr.getLoc(),
S.Context));
return;
case AttributeList::AT_ns_returns_retained:
- d->addAttr(::new (S.Context) NSReturnsRetainedAttr(attr.getLoc(),
+ D->addAttr(::new (S.Context) NSReturnsRetainedAttr(Attr.getLoc(),
S.Context));
return;
};
}
+static void handleObjCOwnershipAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ if (hasDeclarator(D)) return;
+
+ SourceLocation L = Attr.getLoc();
+ S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type)
+ << SourceRange(L, L) << Attr.getName() << 12 /* variable */;
+}
+
+static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ if (!isa<VarDecl>(D) && !isa<FieldDecl>(D)) {
+ SourceLocation L = Attr.getLoc();
+ S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type)
+ << SourceRange(L, L) << Attr.getName() << 12 /* variable */;
+ return;
+ }
+
+ ValueDecl *vd = cast<ValueDecl>(D);
+ QualType type = vd->getType();
+
+ if (!type->isDependentType() &&
+ !type->isObjCLifetimeType()) {
+ S.Diag(Attr.getLoc(), diag::err_objc_precise_lifetime_bad_type)
+ << type;
+ return;
+ }
+
+ Qualifiers::ObjCLifetime lifetime = type.getObjCLifetime();
+
+ // If we have no lifetime yet, check the lifetime we're presumably
+ // going to infer.
+ if (lifetime == Qualifiers::OCL_None && !type->isDependentType())
+ lifetime = type->getObjCARCImplicitLifetime();
+
+ switch (lifetime) {
+ case Qualifiers::OCL_None:
+ assert(type->isDependentType() &&
+ "didn't infer lifetime for non-dependent type?");
+ break;
+
+ case Qualifiers::OCL_Weak: // meaningful
+ case Qualifiers::OCL_Strong: // meaningful
+ break;
+
+ case Qualifiers::OCL_ExplicitNone:
+ case Qualifiers::OCL_Autoreleasing:
+ S.Diag(Attr.getLoc(), diag::warn_objc_precise_lifetime_meaningless)
+ << (lifetime == Qualifiers::OCL_Autoreleasing);
+ break;
+ }
+
+ D->addAttr(::new (S.Context)
+ ObjCPreciseLifetimeAttr(Attr.getLoc(), S.Context));
+}
+
static bool isKnownDeclSpecAttr(const AttributeList &Attr) {
return Attr.getKind() == AttributeList::AT_dllimport ||
Attr.getKind() == AttributeList::AT_dllexport ||
@@ -2745,13 +2833,12 @@ static bool isKnownDeclSpecAttr(const AttributeList &Attr) {
// Microsoft specific attribute handlers.
//===----------------------------------------------------------------------===//
-static void HandleUuidAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (S.LangOpts.Microsoft || S.LangOpts.Borland) {
// check the attribute arguments.
- if (Attr.getNumArgs() != 1) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ if (!checkAttributeNumArgs(S, Attr, 1))
return;
- }
+
Expr *Arg = Attr.getArg(0);
StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
if (Str == 0 || Str->isWide()) {
@@ -2794,7 +2881,7 @@ static void HandleUuidAttr(Decl *d, const AttributeList &Attr, Sema &S) {
I++;
}
- d->addAttr(::new (S.Context) UuidAttr(Attr.getLoc(), S.Context,
+ D->addAttr(::new (S.Context) UuidAttr(Attr.getLoc(), S.Context,
Str->getString()));
} else
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "uuid";
@@ -2804,24 +2891,24 @@ static void HandleUuidAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// Top Level Sema Entry Points
//===----------------------------------------------------------------------===//
-static void ProcessNonInheritableDeclAttr(Scope *scope, Decl *D,
- const AttributeList &Attr, Sema &S) {
+static void ProcessNonInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
+ const AttributeList &Attr) {
switch (Attr.getKind()) {
- case AttributeList::AT_device: HandleDeviceAttr (D, Attr, S); break;
- case AttributeList::AT_host: HandleHostAttr (D, Attr, S); break;
- case AttributeList::AT_overloadable:HandleOverloadableAttr(D, Attr, S); break;
+ case AttributeList::AT_device: handleDeviceAttr (S, D, Attr); break;
+ case AttributeList::AT_host: handleHostAttr (S, D, Attr); break;
+ case AttributeList::AT_overloadable:handleOverloadableAttr(S, D, Attr); break;
default:
break;
}
}
-static void ProcessInheritableDeclAttr(Scope *scope, Decl *D,
- const AttributeList &Attr, Sema &S) {
+static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
+ const AttributeList &Attr) {
switch (Attr.getKind()) {
- case AttributeList::AT_IBAction: HandleIBAction(D, Attr, S); break;
- case AttributeList::AT_IBOutlet: HandleIBOutlet(D, Attr, S); break;
+ case AttributeList::AT_IBAction: handleIBAction(S, D, Attr); break;
+ case AttributeList::AT_IBOutlet: handleIBOutlet(S, D, Attr); break;
case AttributeList::AT_IBOutletCollection:
- HandleIBOutletCollection(D, Attr, S); break;
+ handleIBOutletCollection(S, D, Attr); break;
case AttributeList::AT_address_space:
case AttributeList::AT_opencl_image_access:
case AttributeList::AT_objc_gc:
@@ -2837,100 +2924,108 @@ static void ProcessInheritableDeclAttr(Scope *scope, Decl *D,
// Ignore, this is a non-inheritable attribute, handled
// by ProcessNonInheritableDeclAttr.
break;
- case AttributeList::AT_alias: HandleAliasAttr (D, Attr, S); break;
- case AttributeList::AT_aligned: HandleAlignedAttr (D, Attr, S); break;
+ case AttributeList::AT_alias: handleAliasAttr (S, D, Attr); break;
+ case AttributeList::AT_aligned: handleAlignedAttr (S, D, Attr); break;
case AttributeList::AT_always_inline:
- HandleAlwaysInlineAttr (D, Attr, S); break;
+ handleAlwaysInlineAttr (S, D, Attr); break;
case AttributeList::AT_analyzer_noreturn:
- HandleAnalyzerNoReturnAttr (D, Attr, S); break;
- case AttributeList::AT_annotate: HandleAnnotateAttr (D, Attr, S); break;
- case AttributeList::AT_availability:HandleAvailabilityAttr(D, Attr, S); break;
+ handleAnalyzerNoReturnAttr (S, D, Attr); break;
+ case AttributeList::AT_annotate: handleAnnotateAttr (S, D, Attr); break;
+ case AttributeList::AT_availability:handleAvailabilityAttr(S, D, Attr); break;
case AttributeList::AT_carries_dependency:
- HandleDependencyAttr (D, Attr, S); break;
- case AttributeList::AT_common: HandleCommonAttr (D, Attr, S); break;
- case AttributeList::AT_constant: HandleConstantAttr (D, Attr, S); break;
- case AttributeList::AT_constructor: HandleConstructorAttr (D, Attr, S); break;
- case AttributeList::AT_deprecated: HandleDeprecatedAttr (D, Attr, S); break;
- case AttributeList::AT_destructor: HandleDestructorAttr (D, Attr, S); break;
+ handleDependencyAttr (S, D, Attr); break;
+ case AttributeList::AT_common: handleCommonAttr (S, D, Attr); break;
+ case AttributeList::AT_constant: handleConstantAttr (S, D, Attr); break;
+ case AttributeList::AT_constructor: handleConstructorAttr (S, D, Attr); break;
+ case AttributeList::AT_deprecated: handleDeprecatedAttr (S, D, Attr); break;
+ case AttributeList::AT_destructor: handleDestructorAttr (S, D, Attr); break;
case AttributeList::AT_ext_vector_type:
- HandleExtVectorTypeAttr(scope, D, Attr, S);
+ handleExtVectorTypeAttr(S, scope, D, Attr);
break;
- case AttributeList::AT_format: HandleFormatAttr (D, Attr, S); break;
- case AttributeList::AT_format_arg: HandleFormatArgAttr (D, Attr, S); break;
- case AttributeList::AT_global: HandleGlobalAttr (D, Attr, S); break;
- case AttributeList::AT_gnu_inline: HandleGNUInlineAttr (D, Attr, S); break;
+ case AttributeList::AT_format: handleFormatAttr (S, D, Attr); break;
+ case AttributeList::AT_format_arg: handleFormatArgAttr (S, D, Attr); break;
+ case AttributeList::AT_global: handleGlobalAttr (S, D, Attr); break;
+ case AttributeList::AT_gnu_inline: handleGNUInlineAttr (S, D, Attr); break;
case AttributeList::AT_launch_bounds:
- HandleLaunchBoundsAttr(D, Attr, S);
+ handleLaunchBoundsAttr(S, D, Attr);
break;
- case AttributeList::AT_mode: HandleModeAttr (D, Attr, S); break;
- case AttributeList::AT_malloc: HandleMallocAttr (D, Attr, S); break;
- case AttributeList::AT_may_alias: HandleMayAliasAttr (D, Attr, S); break;
- case AttributeList::AT_nocommon: HandleNoCommonAttr (D, Attr, S); break;
- case AttributeList::AT_nonnull: HandleNonNullAttr (D, Attr, S); break;
+ case AttributeList::AT_mode: handleModeAttr (S, D, Attr); break;
+ case AttributeList::AT_malloc: handleMallocAttr (S, D, Attr); break;
+ case AttributeList::AT_may_alias: handleMayAliasAttr (S, D, Attr); break;
+ case AttributeList::AT_nocommon: handleNoCommonAttr (S, D, Attr); break;
+ case AttributeList::AT_nonnull: handleNonNullAttr (S, D, Attr); break;
case AttributeList::AT_ownership_returns:
case AttributeList::AT_ownership_takes:
case AttributeList::AT_ownership_holds:
- HandleOwnershipAttr (D, Attr, S); break;
- case AttributeList::AT_naked: HandleNakedAttr (D, Attr, S); break;
- case AttributeList::AT_noreturn: HandleNoReturnAttr (D, Attr, S); break;
- case AttributeList::AT_nothrow: HandleNothrowAttr (D, Attr, S); break;
- case AttributeList::AT_shared: HandleSharedAttr (D, Attr, S); break;
- case AttributeList::AT_vecreturn: HandleVecReturnAttr (D, Attr, S); break;
+ handleOwnershipAttr (S, D, Attr); break;
+ case AttributeList::AT_naked: handleNakedAttr (S, D, Attr); break;
+ case AttributeList::AT_noreturn: handleNoReturnAttr (S, D, Attr); break;
+ case AttributeList::AT_nothrow: handleNothrowAttr (S, D, Attr); break;
+ case AttributeList::AT_shared: handleSharedAttr (S, D, Attr); break;
+ case AttributeList::AT_vecreturn: handleVecReturnAttr (S, D, Attr); break;
+
+ case AttributeList::AT_objc_ownership:
+ handleObjCOwnershipAttr(S, D, Attr); break;
+ case AttributeList::AT_objc_precise_lifetime:
+ handleObjCPreciseLifetimeAttr(S, D, Attr); break;
// Checker-specific.
case AttributeList::AT_cf_consumed:
- case AttributeList::AT_ns_consumed: HandleNSConsumedAttr (D, Attr, S); break;
+ case AttributeList::AT_ns_consumed: handleNSConsumedAttr (S, D, Attr); break;
case AttributeList::AT_ns_consumes_self:
- HandleNSConsumesSelfAttr(D, Attr, S); break;
+ handleNSConsumesSelfAttr(S, D, Attr); break;
case AttributeList::AT_ns_returns_autoreleased:
case AttributeList::AT_ns_returns_not_retained:
case AttributeList::AT_cf_returns_not_retained:
case AttributeList::AT_ns_returns_retained:
case AttributeList::AT_cf_returns_retained:
- HandleNSReturnsRetainedAttr(D, Attr, S); break;
+ handleNSReturnsRetainedAttr(S, D, Attr); break;
case AttributeList::AT_reqd_wg_size:
- HandleReqdWorkGroupSize(D, Attr, S); break;
+ handleReqdWorkGroupSize(S, D, Attr); break;
case AttributeList::AT_init_priority:
- HandleInitPriorityAttr(D, Attr, S); break;
+ handleInitPriorityAttr(S, D, Attr); break;
- case AttributeList::AT_packed: HandlePackedAttr (D, Attr, S); break;
- case AttributeList::AT_MsStruct: HandleMsStructAttr (D, Attr, S); break;
- case AttributeList::AT_section: HandleSectionAttr (D, Attr, S); break;
- case AttributeList::AT_unavailable: HandleUnavailableAttr (D, Attr, S); break;
- case AttributeList::AT_unused: HandleUnusedAttr (D, Attr, S); break;
- case AttributeList::AT_used: HandleUsedAttr (D, Attr, S); break;
- case AttributeList::AT_visibility: HandleVisibilityAttr (D, Attr, S); break;
- case AttributeList::AT_warn_unused_result: HandleWarnUnusedResult(D,Attr,S);
+ case AttributeList::AT_packed: handlePackedAttr (S, D, Attr); break;
+ case AttributeList::AT_MsStruct: handleMsStructAttr (S, D, Attr); break;
+ case AttributeList::AT_section: handleSectionAttr (S, D, Attr); break;
+ case AttributeList::AT_unavailable: handleUnavailableAttr (S, D, Attr); break;
+ case AttributeList::AT_arc_weakref_unavailable:
+ handleArcWeakrefUnavailableAttr (S, D, Attr);
break;
- case AttributeList::AT_weak: HandleWeakAttr (D, Attr, S); break;
- case AttributeList::AT_weakref: HandleWeakRefAttr (D, Attr, S); break;
- case AttributeList::AT_weak_import: HandleWeakImportAttr (D, Attr, S); break;
+ case AttributeList::AT_unused: handleUnusedAttr (S, D, Attr); break;
+ case AttributeList::AT_used: handleUsedAttr (S, D, Attr); break;
+ case AttributeList::AT_visibility: handleVisibilityAttr (S, D, Attr); break;
+ case AttributeList::AT_warn_unused_result: handleWarnUnusedResult(S, D, Attr);
+ break;
+ case AttributeList::AT_weak: handleWeakAttr (S, D, Attr); break;
+ case AttributeList::AT_weakref: handleWeakRefAttr (S, D, Attr); break;
+ case AttributeList::AT_weak_import: handleWeakImportAttr (S, D, Attr); break;
case AttributeList::AT_transparent_union:
- HandleTransparentUnionAttr(D, Attr, S);
+ handleTransparentUnionAttr(S, D, Attr);
break;
case AttributeList::AT_objc_exception:
- HandleObjCExceptionAttr(D, Attr, S);
+ handleObjCExceptionAttr(S, D, Attr);
break;
case AttributeList::AT_objc_method_family:
- HandleObjCMethodFamilyAttr(D, Attr, S);
+ handleObjCMethodFamilyAttr(S, D, Attr);
break;
- case AttributeList::AT_nsobject: HandleObjCNSObject (D, Attr, S); break;
- case AttributeList::AT_blocks: HandleBlocksAttr (D, Attr, S); break;
- case AttributeList::AT_sentinel: HandleSentinelAttr (D, Attr, S); break;
- case AttributeList::AT_const: HandleConstAttr (D, Attr, S); break;
- case AttributeList::AT_pure: HandlePureAttr (D, Attr, S); break;
- case AttributeList::AT_cleanup: HandleCleanupAttr (D, Attr, S); break;
- case AttributeList::AT_nodebug: HandleNoDebugAttr (D, Attr, S); break;
- case AttributeList::AT_noinline: HandleNoInlineAttr (D, Attr, S); break;
- case AttributeList::AT_regparm: HandleRegparmAttr (D, Attr, S); break;
+ case AttributeList::AT_nsobject: handleObjCNSObject (S, D, Attr); break;
+ case AttributeList::AT_blocks: handleBlocksAttr (S, D, Attr); break;
+ case AttributeList::AT_sentinel: handleSentinelAttr (S, D, Attr); break;
+ case AttributeList::AT_const: handleConstAttr (S, D, Attr); break;
+ case AttributeList::AT_pure: handlePureAttr (S, D, Attr); break;
+ case AttributeList::AT_cleanup: handleCleanupAttr (S, D, Attr); break;
+ case AttributeList::AT_nodebug: handleNoDebugAttr (S, D, Attr); break;
+ case AttributeList::AT_noinline: handleNoInlineAttr (S, D, Attr); break;
+ case AttributeList::AT_regparm: handleRegparmAttr (S, D, Attr); break;
case AttributeList::IgnoredAttribute:
// Just ignore
break;
case AttributeList::AT_no_instrument_function: // Interacts with -pg.
- HandleNoInstrumentFunctionAttr(D, Attr, S);
+ handleNoInstrumentFunctionAttr(S, D, Attr);
break;
case AttributeList::AT_stdcall:
case AttributeList::AT_cdecl:
@@ -2938,13 +3033,13 @@ static void ProcessInheritableDeclAttr(Scope *scope, Decl *D,
case AttributeList::AT_thiscall:
case AttributeList::AT_pascal:
case AttributeList::AT_pcs:
- HandleCallConvAttr(D, Attr, S);
+ handleCallConvAttr(S, D, Attr);
break;
case AttributeList::AT_opencl_kernel_function:
- HandleOpenCLKernelAttr(D, Attr, S);
+ handleOpenCLKernelAttr(S, D, Attr);
break;
case AttributeList::AT_uuid:
- HandleUuidAttr(D, Attr, S);
+ handleUuidAttr(S, D, Attr);
break;
default:
// Ask target about the attribute.
@@ -2960,8 +3055,8 @@ static void ProcessInheritableDeclAttr(Scope *scope, Decl *D,
/// the attribute applies to decls. If the attribute is a type attribute, just
/// silently ignore it if a GNU attribute. FIXME: Applying a C++0x attribute to
/// the wrong thing is illegal (C++0x [dcl.attr.grammar]/4).
-static void ProcessDeclAttribute(Scope *scope, Decl *D,
- const AttributeList &Attr, Sema &S,
+static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
+ const AttributeList &Attr,
bool NonInheritable, bool Inheritable) {
if (Attr.isInvalid())
return;
@@ -2971,10 +3066,10 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D,
return;
if (NonInheritable)
- ProcessNonInheritableDeclAttr(scope, D, Attr, S);
+ ProcessNonInheritableDeclAttr(S, scope, D, Attr);
if (Inheritable)
- ProcessInheritableDeclAttr(scope, D, Attr, S);
+ ProcessInheritableDeclAttr(S, scope, D, Attr);
}
/// ProcessDeclAttributeList - Apply all the decl attributes in the specified
@@ -2983,7 +3078,7 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D,
const AttributeList *AttrList,
bool NonInheritable, bool Inheritable) {
for (const AttributeList* l = AttrList; l; l = l->getNext()) {
- ProcessDeclAttribute(S, D, *l, *this, NonInheritable, Inheritable);
+ ProcessDeclAttribute(*this, S, D, *l, NonInheritable, Inheritable);
}
// GCC accepts
@@ -3085,6 +3180,32 @@ void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD,
ProcessDeclAttributeList(S, D, Attrs, NonInheritable, Inheritable);
}
+/// Is the given declaration allowed to use a forbidden type?
+static bool isForbiddenTypeAllowed(Sema &S, Decl *decl) {
+ // Private ivars are always okay. Unfortunately, people don't
+ // always properly make their ivars private, even in system headers.
+ // Plus we need to make fields okay, too.
+ if (!isa<FieldDecl>(decl) && !isa<ObjCPropertyDecl>(decl))
+ return false;
+
+ // Require it to be declared in a system header.
+ return S.Context.getSourceManager().isInSystemHeader(decl->getLocation());
+}
+
+/// Handle a delayed forbidden-type diagnostic.
+static void handleDelayedForbiddenType(Sema &S, DelayedDiagnostic &diag,
+ Decl *decl) {
+ if (decl && isForbiddenTypeAllowed(S, decl)) {
+ decl->addAttr(new (S.Context) UnavailableAttr(diag.Loc, S.Context,
+ "this system declaration uses an unsupported type"));
+ return;
+ }
+
+ S.Diag(diag.Loc, diag.getForbiddenTypeDiagnostic())
+ << diag.getForbiddenTypeOperand() << diag.getForbiddenTypeArgument();
+ diag.Triggered = true;
+}
+
// This duplicates a vector push_back but hides the need to know the
// size of the type.
void Sema::DelayedDiagnostics::add(const DelayedDiagnostic &diag) {
@@ -3126,7 +3247,7 @@ void Sema::DelayedDiagnostics::popParsingDecl(Sema &S, ParsingDeclState state,
// We only want to actually emit delayed diagnostics when we
// successfully parsed a decl.
- if (decl) {
+ if (decl && !decl->isInvalidDecl()) {
// We emit all the active diagnostics, not just those starting
// from the saved state. The idea is this: we get one push for a
// decl spec and another for each declarator; in a decl group like:
@@ -3147,6 +3268,10 @@ void Sema::DelayedDiagnostics::popParsingDecl(Sema &S, ParsingDeclState state,
case DelayedDiagnostic::Access:
S.HandleDelayedAccessCheck(diag, decl);
break;
+
+ case DelayedDiagnostic::ForbiddenType:
+ handleDelayedForbiddenType(S, diag, decl);
+ break;
}
}
}
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index ce99efbd0bd2..d793daf9d826 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -185,9 +185,9 @@ void Sema::ImplicitExceptionSpecification::CalledExpr(Expr *E) {
// FIXME:
//
// C++0x [except.spec]p14:
- // [An] implicit exception-specification specifies the type-id T if and
- // only if T is allowed by the exception-specification of a function directly
- // invoked by f’s implicit definition; f shall allow all exceptions if any
+ // [An] implicit exception-specification specifies the type-id T if and
+ // only if T is allowed by the exception-specification of a function directly
+ // invoked by f's implicit definition; f shall allow all exceptions if any
// function it directly invokes allows all exceptions, and f shall allow no
// exceptions if every function it directly invokes allows no exceptions.
//
@@ -762,13 +762,6 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases,
QualType NewBaseType
= Context.getCanonicalType(Bases[idx]->getType());
NewBaseType = NewBaseType.getLocalUnqualifiedType();
- if (!Class->hasObjectMember()) {
- if (const RecordType *FDTTy =
- NewBaseType.getTypePtr()->getAs<RecordType>())
- if (FDTTy->getDecl()->hasObjectMember())
- Class->setHasObjectMember(true);
- }
-
if (KnownBaseTypes[NewBaseType]) {
// C++ [class.mi]p3:
// A class shall not be specified as a direct base class of a
@@ -1086,14 +1079,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
assert(!DS.isFriendSpecified());
assert(!Init || !HasDeferredInit);
- bool isFunc = false;
- if (D.isFunctionDeclarator())
- isFunc = true;
- else if (D.getNumTypeObjects() == 0 &&
- D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_typename) {
- QualType TDType = GetTypeFromParser(DS.getRepAsType());
- isFunc = TDType->isFunctionType();
- }
+ bool isFunc = D.isDeclarationOfFunction();
// C++ 9.2p6: A member shall not be declared to have automatic storage
// duration (auto, register) or with the extern storage-class-specifier.
@@ -1440,25 +1426,27 @@ Sema::ActOnMemInitializer(Decl *ConstructorD,
}
// If no results were found, try to correct typos.
+ TypoCorrection Corr;
if (R.empty() && BaseType.isNull() &&
- CorrectTypo(R, S, &SS, ClassDecl, 0, CTC_NoKeywords) &&
- R.isSingleResult()) {
- if (FieldDecl *Member = R.getAsSingle<FieldDecl>()) {
+ (Corr = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), S, &SS,
+ ClassDecl, false, CTC_NoKeywords))) {
+ std::string CorrectedStr(Corr.getAsString(getLangOptions()));
+ std::string CorrectedQuotedStr(Corr.getQuoted(getLangOptions()));
+ if (FieldDecl *Member = Corr.getCorrectionDeclAs<FieldDecl>()) {
if (Member->getDeclContext()->getRedeclContext()->Equals(ClassDecl)) {
// We have found a non-static data member with a similar
// name to what was typed; complain and initialize that
// member.
Diag(R.getNameLoc(), diag::err_mem_init_not_member_or_class_suggest)
- << MemberOrBase << true << R.getLookupName()
- << FixItHint::CreateReplacement(R.getNameLoc(),
- R.getLookupName().getAsString());
+ << MemberOrBase << true << CorrectedQuotedStr
+ << FixItHint::CreateReplacement(R.getNameLoc(), CorrectedStr);
Diag(Member->getLocation(), diag::note_previous_decl)
- << Member->getDeclName();
+ << CorrectedQuotedStr;
return BuildMemberInitializer(Member, (Expr**)Args, NumArgs, IdLoc,
LParenLoc, RParenLoc);
}
- } else if (TypeDecl *Type = R.getAsSingle<TypeDecl>()) {
+ } else if (TypeDecl *Type = Corr.getCorrectionDeclAs<TypeDecl>()) {
const CXXBaseSpecifier *DirectBaseSpec;
const CXXBaseSpecifier *VirtualBaseSpec;
if (FindBaseInitializer(*this, ClassDecl,
@@ -1468,9 +1456,8 @@ Sema::ActOnMemInitializer(Decl *ConstructorD,
// similar name to what was typed; complain and initialize
// that base class.
Diag(R.getNameLoc(), diag::err_mem_init_not_member_or_class_suggest)
- << MemberOrBase << false << R.getLookupName()
- << FixItHint::CreateReplacement(R.getNameLoc(),
- R.getLookupName().getAsString());
+ << MemberOrBase << false << CorrectedQuotedStr
+ << FixItHint::CreateReplacement(R.getNameLoc(), CorrectedStr);
const CXXBaseSpecifier *BaseSpec = DirectBaseSpec? DirectBaseSpec
: VirtualBaseSpec;
@@ -1617,14 +1604,10 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr **Args,
// Can't check initialization for a member of dependent type or when
// any of the arguments are type-dependent expressions.
Init = new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs,
- RParenLoc);
-
- // Erase any temporaries within this evaluation context; we're not
- // going to track them in the AST, since we'll be rebuilding the
- // ASTs during template instantiation.
- ExprTemporaries.erase(
- ExprTemporaries.begin() + ExprEvalContexts.back().NumTemporaries,
- ExprTemporaries.end());
+ RParenLoc,
+ Member->getType().getNonReferenceType());
+
+ DiscardCleanupsInEvaluationContext();
} else {
// Initialize the member.
InitializedEntity MemberEntity =
@@ -1658,8 +1641,9 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr **Args,
// initializer. However, deconstructing the ASTs is a dicey process,
// and this approach is far more likely to get the corner cases right.
if (CurContext->isDependentContext())
- Init = new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs,
- RParenLoc);
+ Init = new (Context) ParenListExpr(
+ Context, LParenLoc, Args, NumArgs, RParenLoc,
+ Member->getType().getNonReferenceType());
else
Init = MemberInit.get();
}
@@ -1715,22 +1699,7 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo,
if (DelegationInit.isInvalid())
return true;
- // If we are in a dependent context, template instantiation will
- // perform this type-checking again. Just save the arguments that we
- // received in a ParenListExpr.
- // FIXME: This isn't quite ideal, since our ASTs don't capture all
- // of the information that we have about the base
- // initializer. However, deconstructing the ASTs is a dicey process,
- // and this approach is far more likely to get the corner cases right.
- if (CurContext->isDependentContext()) {
- ExprResult Init
- = Owned(new (Context) ParenListExpr(Context, LParenLoc, Args,
- NumArgs, RParenLoc));
- return new (Context) CXXCtorInitializer(Context, Loc, LParenLoc,
- Constructor, Init.takeAs<Expr>(),
- RParenLoc);
- }
-
+ assert(!CurContext->isDependentContext());
return new (Context) CXXCtorInitializer(Context, Loc, LParenLoc, Constructor,
DelegationInit.takeAs<Expr>(),
RParenLoc);
@@ -1815,14 +1784,9 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
// any of the arguments are type-dependent expressions.
ExprResult BaseInit
= Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs,
- RParenLoc));
+ RParenLoc, BaseType));
- // Erase any temporaries within this evaluation context; we're not
- // going to track them in the AST, since we'll be rebuilding the
- // ASTs during template instantiation.
- ExprTemporaries.erase(
- ExprTemporaries.begin() + ExprEvalContexts.back().NumTemporaries,
- ExprTemporaries.end());
+ DiscardCleanupsInEvaluationContext();
return new (Context) CXXCtorInitializer(Context, BaseTInfo,
/*IsVirtual=*/false,
@@ -1878,7 +1842,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
if (CurContext->isDependentContext()) {
ExprResult Init
= Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs,
- RParenLoc));
+ RParenLoc, BaseType));
return new (Context) CXXCtorInitializer(Context, BaseTInfo,
BaseSpec->isVirtual(),
LParenLoc,
@@ -1989,6 +1953,11 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
if (ImplicitInitKind == IIK_Copy) {
ParmVarDecl *Param = Constructor->getParamDecl(0);
QualType ParamType = Param->getType().getNonReferenceType();
+
+ // Suppress copying zero-width bitfields.
+ if (const Expr *Width = Field->getBitWidth())
+ if (Width->EvaluateAsInt(SemaRef.Context) == 0)
+ return false;
Expr *MemberExprBase =
DeclRefExpr::Create(SemaRef.Context, NestedNameSpecifierLoc(), Param,
@@ -2134,6 +2103,20 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
}
}
+ if (SemaRef.getLangOptions().ObjCAutoRefCount &&
+ FieldBaseElementType->isObjCRetainableType() &&
+ FieldBaseElementType.getObjCLifetime() != Qualifiers::OCL_None &&
+ FieldBaseElementType.getObjCLifetime() != Qualifiers::OCL_ExplicitNone) {
+ // Instant objects:
+ // Default-initialize Objective-C pointers to NULL.
+ CXXMemberInit
+ = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Field,
+ Loc, Loc,
+ new (SemaRef.Context) ImplicitValueInitExpr(Field->getType()),
+ Loc);
+ return false;
+ }
+
// Nothing to initialize.
CXXMemberInit = 0;
return false;
@@ -2207,11 +2190,8 @@ static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info,
}
}
- // Fallthrough and construct a default initializer for the union as
- // a whole, which can call its default constructor if such a thing exists
- // (C++0x perhaps). FIXME: It's not clear that this is the correct
- // behavior going forward with C++0x, when anonymous unions there are
- // finalized, we should revisit this.
+ // FIXME: C++0x unrestricted unions might call a default constructor here.
+ return false;
} else {
// For structs, we simply descend through to initialize all members where
// necessary.
@@ -2259,11 +2239,10 @@ Sema::SetDelegatingInitializer(CXXConstructorDecl *Constructor,
return false;
}
-bool
-Sema::SetCtorInitializers(CXXConstructorDecl *Constructor,
- CXXCtorInitializer **Initializers,
- unsigned NumInitializers,
- bool AnyErrors) {
+bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor,
+ CXXCtorInitializer **Initializers,
+ unsigned NumInitializers,
+ bool AnyErrors) {
if (Constructor->getDeclContext()->isDependentContext()) {
// Just store the initializers as written, they will be checked during
// instantiation.
@@ -3405,7 +3384,7 @@ void Sema::CheckExplicitlyDefaultedDestructor(CXXDestructorDecl *DD) {
bool Sema::ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD) {
CXXRecordDecl *RD = CD->getParent();
assert(!RD->isDependentType() && "do deletion after instantiation");
- if (!LangOpts.CPlusPlus0x)
+ if (!LangOpts.CPlusPlus0x || RD->isInvalidDecl())
return false;
SourceLocation Loc = CD->getLocation();
@@ -3586,7 +3565,7 @@ bool Sema::ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD) {
bool Sema::ShouldDeleteCopyConstructor(CXXConstructorDecl *CD) {
CXXRecordDecl *RD = CD->getParent();
assert(!RD->isDependentType() && "do deletion after instantiation");
- if (!LangOpts.CPlusPlus0x)
+ if (!LangOpts.CPlusPlus0x || RD->isInvalidDecl())
return false;
SourceLocation Loc = CD->getLocation();
@@ -3636,7 +3615,7 @@ bool Sema::ShouldDeleteCopyConstructor(CXXConstructorDecl *CD) {
// resolution, as applied to B's [copy] constructor, results in an
// ambiguity or a function that is deleted or inaccessible from the
// defaulted constructor
- CXXConstructorDecl *BaseCtor = LookupCopyConstructor(BaseDecl, ArgQuals);
+ CXXConstructorDecl *BaseCtor = LookupCopyingConstructor(BaseDecl, ArgQuals);
if (!BaseCtor || BaseCtor->isDeleted())
return true;
if (CheckConstructorAccess(Loc, BaseCtor, BaseCtor->getAccess(), PDiag()) !=
@@ -3664,7 +3643,7 @@ bool Sema::ShouldDeleteCopyConstructor(CXXConstructorDecl *CD) {
// resolution, as applied to B's [copy] constructor, results in an
// ambiguity or a function that is deleted or inaccessible from the
// defaulted constructor
- CXXConstructorDecl *BaseCtor = LookupCopyConstructor(BaseDecl, ArgQuals);
+ CXXConstructorDecl *BaseCtor = LookupCopyingConstructor(BaseDecl, ArgQuals);
if (!BaseCtor || BaseCtor->isDeleted())
return true;
if (CheckConstructorAccess(Loc, BaseCtor, BaseCtor->getAccess(), PDiag()) !=
@@ -3726,8 +3705,8 @@ bool Sema::ShouldDeleteCopyConstructor(CXXConstructorDecl *CD) {
// cannot be [copied] because overload resolution, as applied to B's
// [copy] constructor, results in an ambiguity or a function that is
// deleted or inaccessible from the defaulted constructor
- CXXConstructorDecl *FieldCtor = LookupCopyConstructor(FieldRecord,
- ArgQuals);
+ CXXConstructorDecl *FieldCtor = LookupCopyingConstructor(FieldRecord,
+ ArgQuals);
if (!FieldCtor || FieldCtor->isDeleted())
return true;
if (CheckConstructorAccess(Loc, FieldCtor, FieldCtor->getAccess(),
@@ -3742,7 +3721,7 @@ bool Sema::ShouldDeleteCopyConstructor(CXXConstructorDecl *CD) {
bool Sema::ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD) {
CXXRecordDecl *RD = MD->getParent();
assert(!RD->isDependentType() && "do deletion after instantiation");
- if (!LangOpts.CPlusPlus0x)
+ if (!LangOpts.CPlusPlus0x || RD->isInvalidDecl())
return false;
SourceLocation Loc = MD->getLocation();
@@ -3752,19 +3731,15 @@ bool Sema::ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD) {
bool Union = RD->isUnion();
- bool ConstArg =
- MD->getParamDecl(0)->getType()->getPointeeType().isConstQualified();
+ unsigned ArgQuals =
+ MD->getParamDecl(0)->getType()->getPointeeType().isConstQualified() ?
+ Qualifiers::Const : 0;
// We do this because we should never actually use an anonymous
// union's constructor.
if (Union && RD->isAnonymousStructOrUnion())
return false;
- DeclarationName OperatorName =
- Context.DeclarationNames.getCXXOperatorName(OO_Equal);
- LookupResult R(*this, OperatorName, Loc, LookupOrdinaryName);
- R.suppressDiagnostics();
-
// FIXME: We should put some diagnostic logic right into this function.
// C++0x [class.copy]/11
@@ -3786,37 +3761,11 @@ bool Sema::ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD) {
// resolution, as applied to B's [copy] assignment operator, results in
// an ambiguity or a function that is deleted or inaccessible from the
// assignment operator
-
- LookupQualifiedName(R, BaseDecl, false);
-
- // Filter out any result that isn't a copy-assignment operator.
- LookupResult::Filter F = R.makeFilter();
- while (F.hasNext()) {
- NamedDecl *D = F.next();
- if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D))
- if (Method->isCopyAssignmentOperator())
- continue;
-
- F.erase();
- }
- F.done();
-
- // Build a fake argument expression
- QualType ArgType = BaseType;
- QualType ThisType = BaseType;
- if (ConstArg)
- ArgType.addConst();
- Expr *Args[] = { new (Context) OpaqueValueExpr(Loc, ThisType, VK_LValue)
- , new (Context) OpaqueValueExpr(Loc, ArgType, VK_LValue)
- };
-
- OverloadCandidateSet OCS((Loc));
- OverloadCandidateSet::iterator Best;
-
- AddFunctionCandidates(R.asUnresolvedSet(), Args, 2, OCS);
-
- if (OCS.BestViableFunction(*this, Loc, Best, false) !=
- OR_Success)
+ CXXMethodDecl *CopyOper = LookupCopyingAssignment(BaseDecl, ArgQuals, false,
+ 0);
+ if (!CopyOper || CopyOper->isDeleted())
+ return true;
+ if (CheckDirectMemberAccess(Loc, CopyOper, PDiag()) != AR_accessible)
return true;
}
@@ -3831,37 +3780,11 @@ bool Sema::ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD) {
// resolution, as applied to B's [copy] assignment operator, results in
// an ambiguity or a function that is deleted or inaccessible from the
// assignment operator
-
- LookupQualifiedName(R, BaseDecl, false);
-
- // Filter out any result that isn't a copy-assignment operator.
- LookupResult::Filter F = R.makeFilter();
- while (F.hasNext()) {
- NamedDecl *D = F.next();
- if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D))
- if (Method->isCopyAssignmentOperator())
- continue;
-
- F.erase();
- }
- F.done();
-
- // Build a fake argument expression
- QualType ArgType = BaseType;
- QualType ThisType = BaseType;
- if (ConstArg)
- ArgType.addConst();
- Expr *Args[] = { new (Context) OpaqueValueExpr(Loc, ThisType, VK_LValue)
- , new (Context) OpaqueValueExpr(Loc, ArgType, VK_LValue)
- };
-
- OverloadCandidateSet OCS((Loc));
- OverloadCandidateSet::iterator Best;
-
- AddFunctionCandidates(R.asUnresolvedSet(), Args, 2, OCS);
-
- if (OCS.BestViableFunction(*this, Loc, Best, false) !=
- OR_Success)
+ CXXMethodDecl *CopyOper = LookupCopyingAssignment(BaseDecl, ArgQuals, false,
+ 0);
+ if (!CopyOper || CopyOper->isDeleted())
+ return true;
+ if (CheckDirectMemberAccess(Loc, CopyOper, PDiag()) != AR_accessible)
return true;
}
@@ -3908,37 +3831,12 @@ bool Sema::ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD) {
return true;
}
- LookupQualifiedName(R, FieldRecord, false);
-
- // Filter out any result that isn't a copy-assignment operator.
- LookupResult::Filter F = R.makeFilter();
- while (F.hasNext()) {
- NamedDecl *D = F.next();
- if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D))
- if (Method->isCopyAssignmentOperator())
- continue;
-
- F.erase();
- }
- F.done();
-
- // Build a fake argument expression
- QualType ArgType = FieldType;
- QualType ThisType = FieldType;
- if (ConstArg)
- ArgType.addConst();
- Expr *Args[] = { new (Context) OpaqueValueExpr(Loc, ThisType, VK_LValue)
- , new (Context) OpaqueValueExpr(Loc, ArgType, VK_LValue)
- };
-
- OverloadCandidateSet OCS((Loc));
- OverloadCandidateSet::iterator Best;
-
- AddFunctionCandidates(R.asUnresolvedSet(), Args, 2, OCS);
-
- if (OCS.BestViableFunction(*this, Loc, Best, false) !=
- OR_Success)
- return true;
+ CXXMethodDecl *CopyOper = LookupCopyingAssignment(FieldRecord, ArgQuals,
+ false, 0);
+ if (!CopyOper || CopyOper->isDeleted())
+ return false;
+ if (CheckDirectMemberAccess(Loc, CopyOper, PDiag()) != AR_accessible)
+ return false;
}
}
@@ -3948,7 +3846,7 @@ bool Sema::ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD) {
bool Sema::ShouldDeleteDestructor(CXXDestructorDecl *DD) {
CXXRecordDecl *RD = DD->getParent();
assert(!RD->isDependentType() && "do deletion after instantiation");
- if (!LangOpts.CPlusPlus0x)
+ if (!LangOpts.CPlusPlus0x || RD->isInvalidDecl())
return false;
SourceLocation Loc = DD->getLocation();
@@ -4806,6 +4704,13 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
// Make our StdNamespace cache point at the first real definition of the
// "std" namespace.
StdNamespace = Namespc;
+
+ // Add this instance of "std" to the set of known namespaces
+ KnownNamespaces[Namespc] = false;
+ } else if (!Namespc->isInline()) {
+ // Since this is an "original" namespace, add it to the known set of
+ // namespaces if it is not an inline namespace.
+ KnownNamespaces[Namespc] = false;
}
PushOnScopeChains(Namespc, DeclRegionScope);
@@ -4941,6 +4846,39 @@ static bool IsUsingDirectiveInToplevelContext(DeclContext *CurContext) {
}
}
+static bool TryNamespaceTypoCorrection(Sema &S, LookupResult &R, Scope *Sc,
+ CXXScopeSpec &SS,
+ SourceLocation IdentLoc,
+ IdentifierInfo *Ident) {
+ R.clear();
+ if (TypoCorrection Corrected = S.CorrectTypo(R.getLookupNameInfo(),
+ R.getLookupKind(), Sc, &SS, NULL,
+ false, S.CTC_NoKeywords, NULL)) {
+ if (Corrected.getCorrectionDeclAs<NamespaceDecl>() ||
+ Corrected.getCorrectionDeclAs<NamespaceAliasDecl>()) {
+ std::string CorrectedStr(Corrected.getAsString(S.getLangOptions()));
+ std::string CorrectedQuotedStr(Corrected.getQuoted(S.getLangOptions()));
+ if (DeclContext *DC = S.computeDeclContext(SS, false))
+ S.Diag(IdentLoc, diag::err_using_directive_member_suggest)
+ << Ident << DC << CorrectedQuotedStr << SS.getRange()
+ << FixItHint::CreateReplacement(IdentLoc, CorrectedStr);
+ else
+ S.Diag(IdentLoc, diag::err_using_directive_suggest)
+ << Ident << CorrectedQuotedStr
+ << FixItHint::CreateReplacement(IdentLoc, CorrectedStr);
+
+ S.Diag(Corrected.getCorrectionDecl()->getLocation(),
+ diag::note_namespace_defined_here) << CorrectedQuotedStr;
+
+ Ident = Corrected.getCorrectionAsIdentifierInfo();
+ R.addDecl(Corrected.getCorrectionDecl());
+ return true;
+ }
+ R.setLookupName(Ident);
+ }
+ return false;
+}
+
Decl *Sema::ActOnUsingDirective(Scope *S,
SourceLocation UsingLoc,
SourceLocation NamespcLoc,
@@ -4969,6 +4907,7 @@ Decl *Sema::ActOnUsingDirective(Scope *S,
return 0;
if (R.empty()) {
+ R.clear();
// Allow "using namespace std;" or "using namespace ::std;" even if
// "std" hasn't been defined yet, for GCC compatibility.
if ((!Qualifier || Qualifier->getKind() == NestedNameSpecifier::Global) &&
@@ -4978,27 +4917,7 @@ Decl *Sema::ActOnUsingDirective(Scope *S,
R.resolveKind();
}
// Otherwise, attempt typo correction.
- else if (DeclarationName Corrected = CorrectTypo(R, S, &SS, 0, false,
- CTC_NoKeywords, 0)) {
- if (R.getAsSingle<NamespaceDecl>() ||
- R.getAsSingle<NamespaceAliasDecl>()) {
- if (DeclContext *DC = computeDeclContext(SS, false))
- Diag(IdentLoc, diag::err_using_directive_member_suggest)
- << NamespcName << DC << Corrected << SS.getRange()
- << FixItHint::CreateReplacement(IdentLoc, Corrected.getAsString());
- else
- Diag(IdentLoc, diag::err_using_directive_suggest)
- << NamespcName << Corrected
- << FixItHint::CreateReplacement(IdentLoc, Corrected.getAsString());
- Diag(R.getFoundDecl()->getLocation(), diag::note_namespace_defined_here)
- << Corrected;
-
- NamespcName = Corrected.getAsIdentifierInfo();
- } else {
- R.clear();
- R.setLookupName(NamespcName);
- }
- }
+ else TryNamespaceTypoCorrection(*this, R, S, SS, IdentLoc, NamespcName);
}
if (!R.empty()) {
@@ -5065,6 +4984,7 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S,
assert(S->getFlags() & Scope::DeclScope && "Invalid Scope.");
switch (Name.getKind()) {
+ case UnqualifiedId::IK_ImplicitSelfParam:
case UnqualifiedId::IK_Identifier:
case UnqualifiedId::IK_OperatorFunctionId:
case UnqualifiedId::IK_LiteralOperatorId:
@@ -5916,30 +5836,7 @@ Decl *Sema::ActOnNamespaceAliasDef(Scope *S,
return 0;
if (R.empty()) {
- if (DeclarationName Corrected = CorrectTypo(R, S, &SS, 0, false,
- CTC_NoKeywords, 0)) {
- if (R.getAsSingle<NamespaceDecl>() ||
- R.getAsSingle<NamespaceAliasDecl>()) {
- if (DeclContext *DC = computeDeclContext(SS, false))
- Diag(IdentLoc, diag::err_using_directive_member_suggest)
- << Ident << DC << Corrected << SS.getRange()
- << FixItHint::CreateReplacement(IdentLoc, Corrected.getAsString());
- else
- Diag(IdentLoc, diag::err_using_directive_suggest)
- << Ident << Corrected
- << FixItHint::CreateReplacement(IdentLoc, Corrected.getAsString());
-
- Diag(R.getFoundDecl()->getLocation(), diag::note_namespace_defined_here)
- << Corrected;
-
- Ident = Corrected.getAsIdentifierInfo();
- } else {
- R.clear();
- R.setLookupName(Ident);
- }
- }
-
- if (R.empty()) {
+ if (!TryNamespaceTypoCorrection(*this, R, S, SS, IdentLoc, Ident)) {
Diag(NamespaceLoc, diag::err_expected_namespace_name) << SS.getRange();
return 0;
}
@@ -5982,6 +5879,8 @@ Sema::ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl) {
// An implicitly declared special member function (Clause 12) shall have an
// exception-specification. [...]
ImplicitExceptionSpecification ExceptSpec(Context);
+ if (ClassDecl->isInvalidDecl())
+ return ExceptSpec;
// Direct base-class constructors.
for (CXXRecordDecl::base_class_iterator B = ClassDecl->bases_begin(),
@@ -6355,7 +6254,9 @@ Sema::ComputeDefaultedDtorExceptionSpec(CXXRecordDecl *ClassDecl) {
// An implicitly declared special member function (Clause 12) shall have
// an exception-specification.
ImplicitExceptionSpecification ExceptSpec(Context);
-
+ if (ClassDecl->isInvalidDecl())
+ return ExceptSpec;
+
// Direct base-class destructors.
for (CXXRecordDecl::base_class_iterator B = ClassDecl->bases_begin(),
BEnd = ClassDecl->bases_end();
@@ -6687,61 +6588,12 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T,
Loc, Copy.take());
}
-/// \brief Determine whether the given class has a copy assignment operator
-/// that accepts a const-qualified argument.
-static bool hasConstCopyAssignment(Sema &S, const CXXRecordDecl *CClass) {
- CXXRecordDecl *Class = const_cast<CXXRecordDecl *>(CClass);
-
- if (!Class->hasDeclaredCopyAssignment())
- S.DeclareImplicitCopyAssignment(Class);
-
- QualType ClassType = S.Context.getCanonicalType(S.Context.getTypeDeclType(Class));
- DeclarationName OpName
- = S.Context.DeclarationNames.getCXXOperatorName(OO_Equal);
-
- DeclContext::lookup_const_iterator Op, OpEnd;
- for (llvm::tie(Op, OpEnd) = Class->lookup(OpName); Op != OpEnd; ++Op) {
- // C++ [class.copy]p9:
- // A user-declared copy assignment operator is a non-static non-template
- // member function of class X with exactly one parameter of type X, X&,
- // const X&, volatile X& or const volatile X&.
- const CXXMethodDecl* Method = dyn_cast<CXXMethodDecl>(*Op);
- if (!Method)
- continue;
-
- if (Method->isStatic())
- continue;
- if (Method->getPrimaryTemplate())
- continue;
- const FunctionProtoType *FnType =
- Method->getType()->getAs<FunctionProtoType>();
- assert(FnType && "Overloaded operator has no prototype.");
- // Don't assert on this; an invalid decl might have been left in the AST.
- if (FnType->getNumArgs() != 1 || FnType->isVariadic())
- continue;
- bool AcceptsConst = true;
- QualType ArgType = FnType->getArgType(0);
- if (const LValueReferenceType *Ref = ArgType->getAs<LValueReferenceType>()){
- ArgType = Ref->getPointeeType();
- // Is it a non-const lvalue reference?
- if (!ArgType.isConstQualified())
- AcceptsConst = false;
- }
- if (!S.Context.hasSameUnqualifiedType(ArgType, ClassType))
- continue;
-
- // We have a single argument of type cv X or cv X&, i.e. we've found the
- // copy assignment operator. Return whether it accepts const arguments.
- return AcceptsConst;
- }
- assert(Class->isInvalidDecl() &&
- "No copy assignment operator declared in valid code.");
- return false;
-}
-
std::pair<Sema::ImplicitExceptionSpecification, bool>
Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst(
CXXRecordDecl *ClassDecl) {
+ if (ClassDecl->isInvalidDecl())
+ return std::make_pair(ImplicitExceptionSpecification(Context), false);
+
// C++ [class.copy]p10:
// If the class definition does not explicitly declare a copy
// assignment operator, one is declared implicitly.
@@ -6759,11 +6611,28 @@ Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst(
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
BaseEnd = ClassDecl->bases_end();
HasConstCopyAssignment && Base != BaseEnd; ++Base) {
+ // We'll handle this below
+ if (LangOpts.CPlusPlus0x && Base->isVirtual())
+ continue;
+
assert(!Base->getType()->isDependentType() &&
"Cannot generate implicit members for class with dependent bases.");
- const CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- HasConstCopyAssignment = hasConstCopyAssignment(*this, BaseClassDecl);
+ CXXRecordDecl *BaseClassDecl = Base->getType()->getAsCXXRecordDecl();
+ LookupCopyingAssignment(BaseClassDecl, Qualifiers::Const, false, 0,
+ &HasConstCopyAssignment);
+ }
+
+ // In C++0x, the above citation has "or virtual added"
+ if (LangOpts.CPlusPlus0x) {
+ for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),
+ BaseEnd = ClassDecl->vbases_end();
+ HasConstCopyAssignment && Base != BaseEnd; ++Base) {
+ assert(!Base->getType()->isDependentType() &&
+ "Cannot generate implicit members for class with dependent bases.");
+ CXXRecordDecl *BaseClassDecl = Base->getType()->getAsCXXRecordDecl();
+ LookupCopyingAssignment(BaseClassDecl, Qualifiers::Const, false, 0,
+ &HasConstCopyAssignment);
+ }
}
// -- for all the nonstatic data members of X that are of a class
@@ -6775,10 +6644,9 @@ Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst(
HasConstCopyAssignment && Field != FieldEnd;
++Field) {
QualType FieldType = Context.getBaseElementType((*Field)->getType());
- if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
- const CXXRecordDecl *FieldClassDecl
- = cast<CXXRecordDecl>(FieldClassType->getDecl());
- HasConstCopyAssignment = hasConstCopyAssignment(*this, FieldClassDecl);
+ if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {
+ LookupCopyingAssignment(FieldClassDecl, Qualifiers::Const, false, 0,
+ &HasConstCopyAssignment);
}
}
@@ -6790,36 +6658,48 @@ Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst(
// C++ [except.spec]p14:
// An implicitly declared special member function (Clause 12) shall have an
// exception-specification. [...]
+
+ // It is unspecified whether or not an implicit copy assignment operator
+ // attempts to deduplicate calls to assignment operators of virtual bases are
+ // made. As such, this exception specification is effectively unspecified.
+ // Based on a similar decision made for constness in C++0x, we're erring on
+ // the side of assuming such calls to be made regardless of whether they
+ // actually happen.
ImplicitExceptionSpecification ExceptSpec(Context);
+ unsigned ArgQuals = HasConstCopyAssignment ? Qualifiers::Const : 0;
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
BaseEnd = ClassDecl->bases_end();
Base != BaseEnd; ++Base) {
+ if (Base->isVirtual())
+ continue;
+
CXXRecordDecl *BaseClassDecl
= cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
-
- if (!BaseClassDecl->hasDeclaredCopyAssignment())
- DeclareImplicitCopyAssignment(BaseClassDecl);
+ if (CXXMethodDecl *CopyAssign = LookupCopyingAssignment(BaseClassDecl,
+ ArgQuals, false, 0))
+ ExceptSpec.CalledDecl(CopyAssign);
+ }
- if (CXXMethodDecl *CopyAssign
- = BaseClassDecl->getCopyAssignmentOperator(HasConstCopyAssignment))
+ for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),
+ BaseEnd = ClassDecl->vbases_end();
+ Base != BaseEnd; ++Base) {
+ CXXRecordDecl *BaseClassDecl
+ = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ if (CXXMethodDecl *CopyAssign = LookupCopyingAssignment(BaseClassDecl,
+ ArgQuals, false, 0))
ExceptSpec.CalledDecl(CopyAssign);
}
+
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
FieldEnd = ClassDecl->field_end();
Field != FieldEnd;
++Field) {
QualType FieldType = Context.getBaseElementType((*Field)->getType());
- if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
- CXXRecordDecl *FieldClassDecl
- = cast<CXXRecordDecl>(FieldClassType->getDecl());
-
- if (!FieldClassDecl->hasDeclaredCopyAssignment())
- DeclareImplicitCopyAssignment(FieldClassDecl);
-
- if (CXXMethodDecl *CopyAssign
- = FieldClassDecl->getCopyAssignmentOperator(HasConstCopyAssignment))
- ExceptSpec.CalledDecl(CopyAssign);
- }
+ if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {
+ if (CXXMethodDecl *CopyAssign =
+ LookupCopyingAssignment(FieldClassDecl, ArgQuals, false, 0))
+ ExceptSpec.CalledDecl(CopyAssign);
+ }
}
return std::make_pair(ExceptSpec, HasConstCopyAssignment);
@@ -6875,7 +6755,13 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
PushOnScopeChains(CopyAssignment, S, false);
ClassDecl->addDecl(CopyAssignment);
- if (ShouldDeleteCopyAssignmentOperator(CopyAssignment))
+ // C++0x [class.copy]p18:
+ // ... If the class definition declares a move constructor or move
+ // assignment operator, the implicitly declared copy assignment operator is
+ // defined as deleted; ...
+ if (ClassDecl->hasUserDeclaredMoveConstructor() ||
+ ClassDecl->hasUserDeclaredMoveAssignment() ||
+ ShouldDeleteCopyAssignmentOperator(CopyAssignment))
CopyAssignment->setDeletedAsWritten();
AddOverriddenMethods(ClassDecl, CopyAssignment);
@@ -7014,6 +6900,11 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
Invalid = true;
continue;
}
+
+ // Suppress assigning zero-width bitfields.
+ if (const Expr *Width = Field->getBitWidth())
+ if (Width->EvaluateAsInt(Context) == 0)
+ continue;
QualType FieldType = Field->getType().getNonReferenceType();
if (FieldType->isIncompleteArrayType()) {
@@ -7041,10 +6932,8 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
// explicit assignments, do so. This optimization only applies for arrays
// of scalars and arrays of class type with trivial copy-assignment
// operators.
- if (FieldType->isArrayType() &&
- (!BaseType->isRecordType() ||
- cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl())
- ->hasTrivialCopyAssignment())) {
+ if (FieldType->isArrayType() &&
+ BaseType.hasTrivialCopyAssignment(Context)) {
// Compute the size of the memory buffer to be copied.
QualType SizeType = Context.getSizeType();
llvm::APInt Size(Context.getTypeSize(SizeType),
@@ -7179,6 +7068,9 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
std::pair<Sema::ImplicitExceptionSpecification, bool>
Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) {
+ if (ClassDecl->isInvalidDecl())
+ return std::make_pair(ImplicitExceptionSpecification(Context), false);
+
// C++ [class.copy]p5:
// The implicitly-declared copy constructor for a class X will
// have the form
@@ -7202,8 +7094,8 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) {
CXXRecordDecl *BaseClassDecl
= cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- LookupCopyConstructor(BaseClassDecl, Qualifiers::Const,
- &HasConstCopyConstructor);
+ LookupCopyingConstructor(BaseClassDecl, Qualifiers::Const,
+ &HasConstCopyConstructor);
}
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),
@@ -7212,8 +7104,8 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) {
++Base) {
CXXRecordDecl *BaseClassDecl
= cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- LookupCopyConstructor(BaseClassDecl, Qualifiers::Const,
- &HasConstCopyConstructor);
+ LookupCopyingConstructor(BaseClassDecl, Qualifiers::Const,
+ &HasConstCopyConstructor);
}
// -- for all the nonstatic data members of X that are of a
@@ -7226,8 +7118,8 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) {
++Field) {
QualType FieldType = Context.getBaseElementType((*Field)->getType());
if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {
- LookupCopyConstructor(FieldClassDecl, Qualifiers::Const,
- &HasConstCopyConstructor);
+ LookupCopyingConstructor(FieldClassDecl, Qualifiers::Const,
+ &HasConstCopyConstructor);
}
}
// Otherwise, the implicitly declared copy constructor will have
@@ -7251,7 +7143,7 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) {
CXXRecordDecl *BaseClassDecl
= cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
if (CXXConstructorDecl *CopyConstructor =
- LookupCopyConstructor(BaseClassDecl, Quals))
+ LookupCopyingConstructor(BaseClassDecl, Quals))
ExceptSpec.CalledDecl(CopyConstructor);
}
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),
@@ -7261,7 +7153,7 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) {
CXXRecordDecl *BaseClassDecl
= cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
if (CXXConstructorDecl *CopyConstructor =
- LookupCopyConstructor(BaseClassDecl, Quals))
+ LookupCopyingConstructor(BaseClassDecl, Quals))
ExceptSpec.CalledDecl(CopyConstructor);
}
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
@@ -7271,7 +7163,7 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) {
QualType FieldType = Context.getBaseElementType((*Field)->getType());
if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {
if (CXXConstructorDecl *CopyConstructor =
- LookupCopyConstructor(FieldClassDecl, Quals))
+ LookupCopyingConstructor(FieldClassDecl, Quals))
ExceptSpec.CalledDecl(CopyConstructor);
}
}
@@ -7334,7 +7226,13 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
PushOnScopeChains(CopyConstructor, S, false);
ClassDecl->addDecl(CopyConstructor);
- if (ShouldDeleteCopyConstructor(CopyConstructor))
+ // C++0x [class.copy]p7:
+ // ... If the class definition declares a move constructor or move
+ // assignment operator, the implicitly declared constructor is defined as
+ // deleted; ...
+ if (ClassDecl->hasUserDeclaredMoveConstructor() ||
+ ClassDecl->hasUserDeclaredMoveAssignment() ||
+ ShouldDeleteCopyConstructor(CopyConstructor))
CopyConstructor->setDeletedAsWritten();
return CopyConstructor;
@@ -7523,6 +7421,10 @@ void Sema::AddCXXDirectInitializerToDecl(Decl *RealDecl,
VDecl->setTypeSourceInfo(DeducedType);
VDecl->setType(DeducedType->getType());
+ // In ARC, infer lifetime.
+ if (getLangOptions().ObjCAutoRefCount && inferObjCARCLifetime(VDecl))
+ VDecl->setInvalidDecl();
+
// If this is a redeclaration, check that the type we just deduced matches
// the previously declared type.
if (VarDecl *Old = VDecl->getPreviousDeclaration())
@@ -7605,9 +7507,9 @@ void Sema::AddCXXDirectInitializerToDecl(Decl *RealDecl,
// Store the initialization expressions as a ParenListExpr.
unsigned NumExprs = Exprs.size();
- VDecl->setInit(new (Context) ParenListExpr(Context, LParenLoc,
- (Expr **)Exprs.release(),
- NumExprs, RParenLoc));
+ VDecl->setInit(new (Context) ParenListExpr(
+ Context, LParenLoc, (Expr **)Exprs.release(), NumExprs, RParenLoc,
+ VDecl->getType().getNonReferenceType()));
return;
}
@@ -8143,10 +8045,8 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S,
Diag(Loc, diag::err_objc_object_catch);
Invalid = true;
} else if (T->isObjCObjectPointerType()) {
- if (!getLangOptions().ObjCNonFragileABI) {
- Diag(Loc, diag::err_objc_pointer_cxx_catch_fragile);
- Invalid = true;
- }
+ if (!getLangOptions().ObjCNonFragileABI)
+ Diag(Loc, diag::warn_objc_pointer_cxx_catch_fragile);
}
}
@@ -8154,7 +8054,7 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S,
ExDeclType, TInfo, SC_None, SC_None);
ExDecl->setExceptionVariable(true);
- if (!Invalid) {
+ if (!Invalid && !ExDeclType->isDependentType()) {
if (const RecordType *recordType = ExDeclType->getAs<RecordType>()) {
// C++ [except.handle]p16:
// The object declared in an exception-declaration or, if the
@@ -9020,25 +8920,16 @@ DeclResult Sema::ActOnCXXConditionDeclaration(Scope *S, Declarator &D) {
// new class or enumeration.
assert(D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef &&
"Parser allowed 'typedef' as storage class of condition decl.");
-
- TagDecl *OwnedTag = 0;
- TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S, &OwnedTag);
- QualType Ty = TInfo->getType();
-
- if (Ty->isFunctionType()) { // The declarator shall not specify a function...
- // We exit without creating a CXXConditionDeclExpr because a FunctionDecl
- // would be created and CXXConditionDeclExpr wants a VarDecl.
- Diag(D.getIdentifierLoc(), diag::err_invalid_use_of_function_type)
- << D.getSourceRange();
- return DeclResult();
- } else if (OwnedTag && OwnedTag->isDefinition()) {
- // The type-specifier-seq shall not declare a new class or enumeration.
- Diag(OwnedTag->getLocation(), diag::err_type_defined_in_condition);
- }
-
+
Decl *Dcl = ActOnDeclarator(S, D);
if (!Dcl)
- return DeclResult();
+ return true;
+
+ if (isa<FunctionDecl>(Dcl)) { // The declarator shall not specify a function.
+ Diag(Dcl->getLocation(), diag::err_invalid_use_of_function_type)
+ << D.getSourceRange();
+ return true;
+ }
return Dcl;
}
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index de9097e98b4f..aa8152b03b0a 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -16,14 +16,96 @@
#include "clang/Sema/ExternalSemaSource.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
+#include "clang/AST/ASTConsumer.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/ExprObjC.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceManager.h"
#include "clang/Sema/DeclSpec.h"
#include "llvm/ADT/DenseSet.h"
using namespace clang;
+/// Check whether the given method, which must be in the 'init'
+/// family, is a valid member of that family.
+///
+/// \param receiverTypeIfCall - if null, check this as if declaring it;
+/// if non-null, check this as if making a call to it with the given
+/// receiver type
+///
+/// \return true to indicate that there was an error and appropriate
+/// actions were taken
+bool Sema::checkInitMethod(ObjCMethodDecl *method,
+ QualType receiverTypeIfCall) {
+ if (method->isInvalidDecl()) return true;
+
+ // This castAs is safe: methods that don't return an object
+ // pointer won't be inferred as inits and will reject an explicit
+ // objc_method_family(init).
+
+ // We ignore protocols here. Should we? What about Class?
+
+ const ObjCObjectType *result = method->getResultType()
+ ->castAs<ObjCObjectPointerType>()->getObjectType();
+
+ if (result->isObjCId()) {
+ return false;
+ } else if (result->isObjCClass()) {
+ // fall through: always an error
+ } else {
+ ObjCInterfaceDecl *resultClass = result->getInterface();
+ assert(resultClass && "unexpected object type!");
+
+ // It's okay for the result type to still be a forward declaration
+ // if we're checking an interface declaration.
+ if (resultClass->isForwardDecl()) {
+ if (receiverTypeIfCall.isNull() &&
+ !isa<ObjCImplementationDecl>(method->getDeclContext()))
+ return false;
+
+ // Otherwise, we try to compare class types.
+ } else {
+ // If this method was declared in a protocol, we can't check
+ // anything unless we have a receiver type that's an interface.
+ const ObjCInterfaceDecl *receiverClass = 0;
+ if (isa<ObjCProtocolDecl>(method->getDeclContext())) {
+ if (receiverTypeIfCall.isNull())
+ return false;
+
+ receiverClass = receiverTypeIfCall->castAs<ObjCObjectPointerType>()
+ ->getInterfaceDecl();
+
+ // This can be null for calls to e.g. id<Foo>.
+ if (!receiverClass) return false;
+ } else {
+ receiverClass = method->getClassInterface();
+ assert(receiverClass && "method not associated with a class!");
+ }
+
+ // If either class is a subclass of the other, it's fine.
+ if (receiverClass->isSuperClassOf(resultClass) ||
+ resultClass->isSuperClassOf(receiverClass))
+ return false;
+ }
+ }
+
+ SourceLocation loc = method->getLocation();
+
+ // If we're in a system header, and this is not a call, just make
+ // the method unusable.
+ if (receiverTypeIfCall.isNull() && getSourceManager().isInSystemHeader(loc)) {
+ method->addAttr(new (Context) UnavailableAttr(loc, Context,
+ "init method returns a type unrelated to its receiver type"));
+ return true;
+ }
+
+ // Otherwise, it's an error.
+ Diag(loc, diag::err_arc_init_method_unrelated_result_type);
+ method->setInvalidDecl();
+ return true;
+}
+
bool Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod,
const ObjCMethodDecl *Overridden,
bool IsImplementation) {
@@ -36,7 +118,7 @@ bool Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod,
QualType ResultType = NewMethod->getResultType();
SourceRange ResultTypeRange;
if (const TypeSourceInfo *ResultTypeInfo
- = NewMethod->getResultTypeSourceInfo())
+ = NewMethod->getResultTypeSourceInfo())
ResultTypeRange = ResultTypeInfo->getTypeLoc().getSourceRange();
// Figure out which class this method is part of, if any.
@@ -73,7 +155,15 @@ bool Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod,
return false;
}
-
+/// \brief Check for consistency between a given method declaration and the
+/// methods it overrides within the class hierarchy.
+///
+/// This method walks the inheritance hierarchy starting at the given
+/// declaration context (\p DC), invoking Sema::CheckObjCMethodOverride() with
+/// the given new method (\p NewMethod) and any method it directly overrides
+/// in the hierarchy. Sema::CheckObjCMethodOverride() is responsible for
+/// checking consistency, e.g., among return types for methods that return a
+/// related result type.
static bool CheckObjCMethodOverrides(Sema &S, ObjCMethodDecl *NewMethod,
DeclContext *DC,
bool SkipCurrent = true) {
@@ -99,10 +189,10 @@ static bool CheckObjCMethodOverrides(Sema &S, ObjCMethodDecl *NewMethod,
if (CheckObjCMethodOverrides(S, NewMethod, Category, false))
return true;
}
-
+
// Look through protocols.
for (ObjCList<ObjCProtocolDecl>::iterator I = Class->protocol_begin(),
- IEnd = Class->protocol_end();
+ IEnd = Class->protocol_end();
I != IEnd; ++I)
if (CheckObjCMethodOverrides(S, NewMethod, *I, false))
return true;
@@ -115,7 +205,7 @@ static bool CheckObjCMethodOverrides(Sema &S, ObjCMethodDecl *NewMethod,
if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(DC)) {
// Look through protocols.
for (ObjCList<ObjCProtocolDecl>::iterator I = Category->protocol_begin(),
- IEnd = Category->protocol_end();
+ IEnd = Category->protocol_end();
I != IEnd; ++I)
if (CheckObjCMethodOverrides(S, NewMethod, *I, false))
return true;
@@ -126,7 +216,7 @@ static bool CheckObjCMethodOverrides(Sema &S, ObjCMethodDecl *NewMethod,
if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(DC)) {
// Look through protocols.
for (ObjCList<ObjCProtocolDecl>::iterator I = Protocol->protocol_begin(),
- IEnd = Protocol->protocol_end();
+ IEnd = Protocol->protocol_end();
I != IEnd; ++I)
if (CheckObjCMethodOverrides(S, NewMethod, *I, false))
return true;
@@ -141,13 +231,13 @@ bool Sema::CheckObjCMethodOverrides(ObjCMethodDecl *NewMethod,
DeclContext *DC) {
if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(DC))
return ::CheckObjCMethodOverrides(*this, NewMethod, Class);
-
+
if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(DC))
return ::CheckObjCMethodOverrides(*this, NewMethod, Category);
-
+
if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(DC))
return ::CheckObjCMethodOverrides(*this, NewMethod, Protocol);
-
+
if (ObjCImplementationDecl *Impl = dyn_cast<ObjCImplementationDecl>(DC))
return ::CheckObjCMethodOverrides(*this, NewMethod,
Impl->getClassInterface());
@@ -159,6 +249,55 @@ bool Sema::CheckObjCMethodOverrides(ObjCMethodDecl *NewMethod,
return ::CheckObjCMethodOverrides(*this, NewMethod, CurContext);
}
+/// \brief Check a method declaration for compatibility with the Objective-C
+/// ARC conventions.
+static bool CheckARCMethodDecl(Sema &S, ObjCMethodDecl *method) {
+ ObjCMethodFamily family = method->getMethodFamily();
+ switch (family) {
+ case OMF_None:
+ case OMF_dealloc:
+ case OMF_retain:
+ case OMF_release:
+ case OMF_autorelease:
+ case OMF_retainCount:
+ case OMF_self:
+ return false;
+
+ case OMF_init:
+ // If the method doesn't obey the init rules, don't bother annotating it.
+ if (S.checkInitMethod(method, QualType()))
+ return true;
+
+ method->addAttr(new (S.Context) NSConsumesSelfAttr(SourceLocation(),
+ S.Context));
+
+ // Don't add a second copy of this attribute, but otherwise don't
+ // let it be suppressed.
+ if (method->hasAttr<NSReturnsRetainedAttr>())
+ return false;
+ break;
+
+ case OMF_alloc:
+ case OMF_copy:
+ case OMF_mutableCopy:
+ case OMF_new:
+ if (method->hasAttr<NSReturnsRetainedAttr>() ||
+ method->hasAttr<NSReturnsNotRetainedAttr>() ||
+ method->hasAttr<NSReturnsAutoreleasedAttr>())
+ return false;
+ break;
+
+ case OMF_performSelector:
+ // we don't annotate performSelector's
+ return true;
+
+ }
+
+ method->addAttr(new (S.Context) NSReturnsRetainedAttr(SourceLocation(),
+ S.Context));
+ return false;
+}
+
static void DiagnoseObjCImplementedDeprecations(Sema &S,
NamedDecl *ND,
SourceLocation ImplLoc,
@@ -212,6 +351,31 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
if ((*PI)->getIdentifier())
PushOnScopeChains(*PI, FnBodyScope);
}
+
+ // In ARC, disallow definition of retain/release/autorelease/retainCount
+ if (getLangOptions().ObjCAutoRefCount) {
+ switch (MDecl->getMethodFamily()) {
+ case OMF_retain:
+ case OMF_retainCount:
+ case OMF_release:
+ case OMF_autorelease:
+ Diag(MDecl->getLocation(), diag::err_arc_illegal_method_def)
+ << MDecl->getSelector();
+ break;
+
+ case OMF_None:
+ case OMF_dealloc:
+ case OMF_alloc:
+ case OMF_init:
+ case OMF_mutableCopy:
+ case OMF_copy:
+ case OMF_new:
+ case OMF_self:
+ case OMF_performSelector:
+ break;
+ }
+ }
+
// Warn on implementating deprecated methods under
// -Wdeprecated-implementations flag.
if (ObjCInterfaceDecl *IC = MDecl->getClassInterface())
@@ -284,9 +448,10 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
if (!PrevDecl) {
// Try to correct for a typo in the superclass name.
- LookupResult R(*this, SuperName, SuperLoc, LookupOrdinaryName);
- if (CorrectTypo(R, TUScope, 0, 0, false, CTC_NoKeywords) &&
- (PrevDecl = R.getAsSingle<ObjCInterfaceDecl>())) {
+ TypoCorrection Corrected = CorrectTypo(
+ DeclarationNameInfo(SuperName, SuperLoc), LookupOrdinaryName, TUScope,
+ NULL, NULL, false, CTC_NoKeywords);
+ if ((PrevDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>())) {
Diag(SuperLoc, diag::err_undef_superclass_suggest)
<< SuperName << ClassName << PrevDecl->getDeclName();
Diag(PrevDecl->getLocation(), diag::note_previous_decl)
@@ -333,10 +498,13 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
if (!SuperClassDecl)
Diag(SuperLoc, diag::err_undef_superclass)
<< SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc);
- else if (SuperClassDecl->isForwardDecl())
- Diag(SuperLoc, diag::err_undef_superclass)
+ else if (SuperClassDecl->isForwardDecl()) {
+ Diag(SuperLoc, diag::err_forward_superclass)
<< SuperClassDecl->getDeclName() << ClassName
<< SourceRange(AtInterfaceLoc, ClassLoc);
+ Diag(SuperClassDecl->getLocation(), diag::note_forward_class);
+ SuperClassDecl = 0;
+ }
}
IDecl->setSuperClass(SuperClassDecl);
IDecl->setSuperClassLoc(SuperLoc);
@@ -494,12 +662,12 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations,
ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolId[i].first,
ProtocolId[i].second);
if (!PDecl) {
- LookupResult R(*this, ProtocolId[i].first, ProtocolId[i].second,
- LookupObjCProtocolName);
- if (CorrectTypo(R, TUScope, 0, 0, false, CTC_NoKeywords) &&
- (PDecl = R.getAsSingle<ObjCProtocolDecl>())) {
+ TypoCorrection Corrected = CorrectTypo(
+ DeclarationNameInfo(ProtocolId[i].first, ProtocolId[i].second),
+ LookupObjCProtocolName, TUScope, NULL, NULL, false, CTC_NoKeywords);
+ if ((PDecl = Corrected.getCorrectionDeclAs<ObjCProtocolDecl>())) {
Diag(ProtocolId[i].second, diag::err_undeclared_protocol_suggest)
- << ProtocolId[i].first << R.getLookupName();
+ << ProtocolId[i].first << Corrected.getCorrection();
Diag(PDecl->getLocation(), diag::note_previous_decl)
<< PDecl->getDeclName();
}
@@ -736,20 +904,20 @@ Decl *Sema::ActOnStartClassImplementation(
} else {
// We did not find anything with the name ClassName; try to correct for
// typos in the class name.
- LookupResult R(*this, ClassName, ClassLoc, LookupOrdinaryName);
- if (CorrectTypo(R, TUScope, 0, 0, false, CTC_NoKeywords) &&
- (IDecl = R.getAsSingle<ObjCInterfaceDecl>())) {
+ TypoCorrection Corrected = CorrectTypo(
+ DeclarationNameInfo(ClassName, ClassLoc), LookupOrdinaryName, TUScope,
+ NULL, NULL, false, CTC_NoKeywords);
+ if ((IDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>())) {
// Suggest the (potentially) correct interface name. However, put the
// fix-it hint itself in a separate note, since changing the name in
// the warning would make the fix-it change semantics.However, don't
// provide a code-modification hint or use the typo name for recovery,
// because this is just a warning. The program may actually be correct.
+ DeclarationName CorrectedName = Corrected.getCorrection();
Diag(ClassLoc, diag::warn_undef_interface_suggest)
- << ClassName << R.getLookupName();
- Diag(IDecl->getLocation(), diag::note_previous_decl)
- << R.getLookupName()
- << FixItHint::CreateReplacement(ClassLoc,
- R.getLookupName().getAsString());
+ << ClassName << CorrectedName;
+ Diag(IDecl->getLocation(), diag::note_previous_decl) << CorrectedName
+ << FixItHint::CreateReplacement(ClassLoc, CorrectedName.getAsString());
IDecl = 0;
} else {
Diag(ClassLoc, diag::warn_undef_interface) << ClassName;
@@ -915,6 +1083,9 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl,
void Sema::WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method,
bool &IncompleteImpl, unsigned DiagID) {
+ // No point warning no definition of method which is 'unavailable'.
+ if (method->hasAttr<UnavailableAttr>())
+ return;
if (!IncompleteImpl) {
Diag(ImpLoc, diag::warn_incomplete_impl);
IncompleteImpl = true;
@@ -1091,11 +1262,84 @@ static void CheckMethodOverrideParam(Sema &S,
S.Diag(IfaceVar->getLocation(), diag::note_previous_definition)
<< getTypeRange(IfaceVar->getTypeSourceInfo());
}
-
+
+/// In ARC, check whether the conventional meanings of the two methods
+/// match. If they don't, it's a hard error.
+static bool checkMethodFamilyMismatch(Sema &S, ObjCMethodDecl *impl,
+ ObjCMethodDecl *decl) {
+ ObjCMethodFamily implFamily = impl->getMethodFamily();
+ ObjCMethodFamily declFamily = decl->getMethodFamily();
+ if (implFamily == declFamily) return false;
+
+ // Since conventions are sorted by selector, the only possibility is
+ // that the types differ enough to cause one selector or the other
+ // to fall out of the family.
+ assert(implFamily == OMF_None || declFamily == OMF_None);
+
+ // No further diagnostics required on invalid declarations.
+ if (impl->isInvalidDecl() || decl->isInvalidDecl()) return true;
+
+ const ObjCMethodDecl *unmatched = impl;
+ ObjCMethodFamily family = declFamily;
+ unsigned errorID = diag::err_arc_lost_method_convention;
+ unsigned noteID = diag::note_arc_lost_method_convention;
+ if (declFamily == OMF_None) {
+ unmatched = decl;
+ family = implFamily;
+ errorID = diag::err_arc_gained_method_convention;
+ noteID = diag::note_arc_gained_method_convention;
+ }
+
+ // Indexes into a %select clause in the diagnostic.
+ enum FamilySelector {
+ F_alloc, F_copy, F_mutableCopy = F_copy, F_init, F_new
+ };
+ FamilySelector familySelector = FamilySelector();
+
+ switch (family) {
+ case OMF_None: llvm_unreachable("logic error, no method convention");
+ case OMF_retain:
+ case OMF_release:
+ case OMF_autorelease:
+ case OMF_dealloc:
+ case OMF_retainCount:
+ case OMF_self:
+ case OMF_performSelector:
+ // Mismatches for these methods don't change ownership
+ // conventions, so we don't care.
+ return false;
+
+ case OMF_init: familySelector = F_init; break;
+ case OMF_alloc: familySelector = F_alloc; break;
+ case OMF_copy: familySelector = F_copy; break;
+ case OMF_mutableCopy: familySelector = F_mutableCopy; break;
+ case OMF_new: familySelector = F_new; break;
+ }
+
+ enum ReasonSelector { R_NonObjectReturn, R_UnrelatedReturn };
+ ReasonSelector reasonSelector;
+
+ // The only reason these methods don't fall within their families is
+ // due to unusual result types.
+ if (unmatched->getResultType()->isObjCObjectPointerType()) {
+ reasonSelector = R_UnrelatedReturn;
+ } else {
+ reasonSelector = R_NonObjectReturn;
+ }
+
+ S.Diag(impl->getLocation(), errorID) << familySelector << reasonSelector;
+ S.Diag(decl->getLocation(), noteID) << familySelector << reasonSelector;
+
+ return true;
+}
void Sema::WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethodDecl,
ObjCMethodDecl *MethodDecl,
bool IsProtocolMethodDecl) {
+ if (getLangOptions().ObjCAutoRefCount &&
+ checkMethodFamilyMismatch(*this, ImpMethodDecl, MethodDecl))
+ return;
+
CheckMethodOverrideReturn(*this, ImpMethodDecl, MethodDecl,
IsProtocolMethodDecl);
@@ -1204,7 +1448,7 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
CheckProtocolMethodDefs(ImpLoc, *PI, IncompleteImpl, InsMap, ClsMap, IDecl);
}
-/// MatchAllMethodDeclarations - Check methods declaraed in interface or
+/// MatchAllMethodDeclarations - Check methods declared in interface
/// or protocol against those declared in their implementations.
///
void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap,
@@ -1422,48 +1666,117 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
return CDecl;
}
+static bool tryMatchRecordTypes(ASTContext &Context,
+ Sema::MethodMatchStrategy strategy,
+ const Type *left, const Type *right);
+
+static bool matchTypes(ASTContext &Context, Sema::MethodMatchStrategy strategy,
+ QualType leftQT, QualType rightQT) {
+ const Type *left =
+ Context.getCanonicalType(leftQT).getUnqualifiedType().getTypePtr();
+ const Type *right =
+ Context.getCanonicalType(rightQT).getUnqualifiedType().getTypePtr();
+
+ if (left == right) return true;
+
+ // If we're doing a strict match, the types have to match exactly.
+ if (strategy == Sema::MMS_strict) return false;
+
+ if (left->isIncompleteType() || right->isIncompleteType()) return false;
+
+ // Otherwise, use this absurdly complicated algorithm to try to
+ // validate the basic, low-level compatibility of the two types.
+
+ // As a minimum, require the sizes and alignments to match.
+ if (Context.getTypeInfo(left) != Context.getTypeInfo(right))
+ return false;
+
+ // Consider all the kinds of non-dependent canonical types:
+ // - functions and arrays aren't possible as return and parameter types
+
+ // - vector types of equal size can be arbitrarily mixed
+ if (isa<VectorType>(left)) return isa<VectorType>(right);
+ if (isa<VectorType>(right)) return false;
+
+ // - references should only match references of identical type
+ // - structs, unions, and Objective-C objects must match more-or-less
+ // exactly
+ // - everything else should be a scalar
+ if (!left->isScalarType() || !right->isScalarType())
+ return tryMatchRecordTypes(Context, strategy, left, right);
+
+ // Make scalars agree in kind, except count bools as chars.
+ Type::ScalarTypeKind leftSK = left->getScalarTypeKind();
+ Type::ScalarTypeKind rightSK = right->getScalarTypeKind();
+ if (leftSK == Type::STK_Bool) leftSK = Type::STK_Integral;
+ if (rightSK == Type::STK_Bool) rightSK = Type::STK_Integral;
+
+ // Note that data member pointers and function member pointers don't
+ // intermix because of the size differences.
+
+ return (leftSK == rightSK);
+}
+
+static bool tryMatchRecordTypes(ASTContext &Context,
+ Sema::MethodMatchStrategy strategy,
+ const Type *lt, const Type *rt) {
+ assert(lt && rt && lt != rt);
+
+ if (!isa<RecordType>(lt) || !isa<RecordType>(rt)) return false;
+ RecordDecl *left = cast<RecordType>(lt)->getDecl();
+ RecordDecl *right = cast<RecordType>(rt)->getDecl();
+
+ // Require union-hood to match.
+ if (left->isUnion() != right->isUnion()) return false;
+
+ // Require an exact match if either is non-POD.
+ if ((isa<CXXRecordDecl>(left) && !cast<CXXRecordDecl>(left)->isPOD()) ||
+ (isa<CXXRecordDecl>(right) && !cast<CXXRecordDecl>(right)->isPOD()))
+ return false;
+
+ // Require size and alignment to match.
+ if (Context.getTypeInfo(lt) != Context.getTypeInfo(rt)) return false;
+
+ // Require fields to match.
+ RecordDecl::field_iterator li = left->field_begin(), le = left->field_end();
+ RecordDecl::field_iterator ri = right->field_begin(), re = right->field_end();
+ for (; li != le && ri != re; ++li, ++ri) {
+ if (!matchTypes(Context, strategy, li->getType(), ri->getType()))
+ return false;
+ }
+ return (li == le && ri == re);
+}
/// MatchTwoMethodDeclarations - Checks that two methods have matching type and
/// returns true, or false, accordingly.
/// TODO: Handle protocol list; such as id<p1,p2> in type comparisons
-bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *Method,
- const ObjCMethodDecl *PrevMethod,
- bool matchBasedOnSizeAndAlignment,
- bool matchBasedOnStrictEqulity) {
- QualType T1 = Context.getCanonicalType(Method->getResultType());
- QualType T2 = Context.getCanonicalType(PrevMethod->getResultType());
-
- if (T1 != T2) {
- // The result types are different.
- if (!matchBasedOnSizeAndAlignment || matchBasedOnStrictEqulity)
- return false;
- // Incomplete types don't have a size and alignment.
- if (T1->isIncompleteType() || T2->isIncompleteType())
- return false;
- // Check is based on size and alignment.
- if (Context.getTypeInfo(T1) != Context.getTypeInfo(T2))
- return false;
- }
+bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *left,
+ const ObjCMethodDecl *right,
+ MethodMatchStrategy strategy) {
+ if (!matchTypes(Context, strategy,
+ left->getResultType(), right->getResultType()))
+ return false;
- ObjCMethodDecl::param_iterator ParamI = Method->param_begin(),
- E = Method->param_end();
- ObjCMethodDecl::param_iterator PrevI = PrevMethod->param_begin();
+ if (getLangOptions().ObjCAutoRefCount &&
+ (left->hasAttr<NSReturnsRetainedAttr>()
+ != right->hasAttr<NSReturnsRetainedAttr>() ||
+ left->hasAttr<NSConsumesSelfAttr>()
+ != right->hasAttr<NSConsumesSelfAttr>()))
+ return false;
- for (; ParamI != E; ++ParamI, ++PrevI) {
- assert(PrevI != PrevMethod->param_end() && "Param mismatch");
- T1 = Context.getCanonicalType((*ParamI)->getType());
- T2 = Context.getCanonicalType((*PrevI)->getType());
- if (T1 != T2) {
- // The result types are different.
- if (!matchBasedOnSizeAndAlignment || matchBasedOnStrictEqulity)
- return false;
- // Incomplete types don't have a size and alignment.
- if (T1->isIncompleteType() || T2->isIncompleteType())
- return false;
- // Check is based on size and alignment.
- if (Context.getTypeInfo(T1) != Context.getTypeInfo(T2))
- return false;
- }
+ ObjCMethodDecl::param_iterator
+ li = left->param_begin(), le = left->param_end(), ri = right->param_begin();
+
+ for (; li != le; ++li, ++ri) {
+ assert(ri != right->param_end() && "Param mismatch");
+ ParmVarDecl *lparm = *li, *rparm = *ri;
+
+ if (!matchTypes(Context, strategy, lparm->getType(), rparm->getType()))
+ return false;
+
+ if (getLangOptions().ObjCAutoRefCount &&
+ lparm->hasAttr<NSConsumedAttr>() != rparm->hasAttr<NSConsumedAttr>())
+ return false;
}
return true;
}
@@ -1505,8 +1818,10 @@ void Sema::AddMethodToGlobalPool(ObjCMethodDecl *Method, bool impl,
// We've seen a method with this name, see if we have already seen this type
// signature.
- for (ObjCMethodList *List = &Entry; List; List = List->Next)
- if (MatchTwoMethodDeclarations(Method, List->Method)) {
+ for (ObjCMethodList *List = &Entry; List; List = List->Next) {
+ bool match = MatchTwoMethodDeclarations(Method, List->Method);
+
+ if (match) {
ObjCMethodDecl *PrevObjCMethod = List->Method;
PrevObjCMethod->setDefined(impl);
// If a method is deprecated, push it in the global pool.
@@ -1523,6 +1838,7 @@ void Sema::AddMethodToGlobalPool(ObjCMethodDecl *Method, bool impl,
}
return;
}
+ }
// We have a new signature for an existing method - add it.
// This is extremely rare. Only 1% of Cocoa selectors are "overloaded".
@@ -1530,6 +1846,25 @@ void Sema::AddMethodToGlobalPool(ObjCMethodDecl *Method, bool impl,
Entry.Next = new (Mem) ObjCMethodList(Method, Entry.Next);
}
+/// Determines if this is an "acceptable" loose mismatch in the global
+/// method pool. This exists mostly as a hack to get around certain
+/// global mismatches which we can't afford to make warnings / errors.
+/// Really, what we want is a way to take a method out of the global
+/// method pool.
+static bool isAcceptableMethodMismatch(ObjCMethodDecl *chosen,
+ ObjCMethodDecl *other) {
+ if (!chosen->isInstanceMethod())
+ return false;
+
+ Selector sel = chosen->getSelector();
+ if (!sel.isUnarySelector() || sel.getNameForSlot(0) != "length")
+ return false;
+
+ // Don't complain about mismatches for -length if the method we
+ // chose has an integral result type.
+ return (chosen->getResultType()->isIntegerType());
+}
+
ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R,
bool receiverIdOrClass,
bool warn, bool instance) {
@@ -1543,32 +1878,52 @@ ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R,
ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second;
- bool strictSelectorMatch = receiverIdOrClass && warn &&
- (Diags.getDiagnosticLevel(diag::warn_strict_multiple_method_decl,
- R.getBegin()) !=
- Diagnostic::Ignored);
if (warn && MethList.Method && MethList.Next) {
- bool issueWarning = false;
+ bool issueDiagnostic = false, issueError = false;
+
+ // We support a warning which complains about *any* difference in
+ // method signature.
+ bool strictSelectorMatch =
+ (receiverIdOrClass && warn &&
+ (Diags.getDiagnosticLevel(diag::warn_strict_multiple_method_decl,
+ R.getBegin()) !=
+ Diagnostic::Ignored));
if (strictSelectorMatch)
for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) {
- // This checks if the methods differ in type mismatch.
- if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method, false, true))
- issueWarning = true;
+ if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method,
+ MMS_strict)) {
+ issueDiagnostic = true;
+ break;
+ }
}
- if (!issueWarning)
+ // If we didn't see any strict differences, we won't see any loose
+ // differences. In ARC, however, we also need to check for loose
+ // mismatches, because most of them are errors.
+ if (!strictSelectorMatch ||
+ (issueDiagnostic && getLangOptions().ObjCAutoRefCount))
for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) {
- // This checks if the methods differ by size & alignment.
- if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method, true))
- issueWarning = true;
+ // This checks if the methods differ in type mismatch.
+ if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method,
+ MMS_loose) &&
+ !isAcceptableMethodMismatch(MethList.Method, Next->Method)) {
+ issueDiagnostic = true;
+ if (getLangOptions().ObjCAutoRefCount)
+ issueError = true;
+ break;
+ }
}
- if (issueWarning) {
- if (strictSelectorMatch)
+ if (issueDiagnostic) {
+ if (issueError)
+ Diag(R.getBegin(), diag::err_arc_multiple_method_decl) << Sel << R;
+ else if (strictSelectorMatch)
Diag(R.getBegin(), diag::warn_strict_multiple_method_decl) << Sel << R;
else
Diag(R.getBegin(), diag::warn_multiple_method_decl) << Sel << R;
- Diag(MethList.Method->getLocStart(), diag::note_using)
+
+ Diag(MethList.Method->getLocStart(),
+ issueError ? diag::note_possibility : diag::note_using)
<< MethList.Method->getSourceRange();
for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next)
Diag(Next->Method->getLocStart(), diag::note_also_found)
@@ -1796,6 +2151,7 @@ void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
DefaultSynthesizeProperties(S, IC, IDecl);
ImplMethodsVsClassMethods(S, IC, IDecl);
AtomicPropertySetterGetterRules(IC, IDecl);
+ DiagnoseOwningPropertyGetterSynthesis(IC);
if (LangOpts.ObjCNonFragileABI2)
while (IDecl->getSuperClass()) {
@@ -1968,7 +2324,7 @@ Decl *Sema::ActOnMethodDeclaration(
} else {
ArgType = GetTypeFromParser(ArgInfo[i].Type, &DI);
// Perform the default array/function conversions (C99 6.7.5.3p[7,8]).
- ArgType = adjustParameterType(ArgType);
+ ArgType = Context.getAdjustedParameterType(ArgType);
}
LookupResult R(*this, ArgInfo[i].Name, ArgInfo[i].NameLoc,
@@ -2015,7 +2371,7 @@ Decl *Sema::ActOnMethodDeclaration(
ArgType = Context.getObjCIdType();
else
// Perform the default array/function conversions (C99 6.7.5.3p[7,8]).
- ArgType = adjustParameterType(ArgType);
+ ArgType = Context.getAdjustedParameterType(ArgType);
if (ArgType->isObjCObjectType()) {
Diag(Param->getLocation(),
diag::err_object_cannot_be_passed_returned_by_value)
@@ -2104,7 +2460,11 @@ Decl *Sema::ActOnMethodDeclaration(
mergeObjCMethodDecls(ObjCMethod, InterfaceMD);
}
- if (!ObjCMethod->hasRelatedResultType() &&
+ bool ARCError = false;
+ if (getLangOptions().ObjCAutoRefCount)
+ ARCError = CheckARCMethodDecl(*this, ObjCMethod);
+
+ if (!ObjCMethod->hasRelatedResultType() && !ARCError &&
getLangOptions().ObjCInferRelatedResultType) {
bool InferRelatedResultType = false;
switch (ObjCMethod->getMethodFamily()) {
@@ -2114,6 +2474,7 @@ Decl *Sema::ActOnMethodDeclaration(
case OMF_mutableCopy:
case OMF_release:
case OMF_retainCount:
+ case OMF_performSelector:
break;
case OMF_alloc:
@@ -2255,15 +2616,8 @@ Decl *Sema::ActOnObjCExceptionDecl(Scope *S, Declarator &D) {
if (getLangOptions().CPlusPlus)
CheckExtraCXXDefaultArguments(D);
- TagDecl *OwnedDecl = 0;
- TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S, &OwnedDecl);
+ TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);
QualType ExceptionType = TInfo->getType();
-
- if (getLangOptions().CPlusPlus && OwnedDecl && OwnedDecl->isDefinition()) {
- // Objective-C++: Types shall not be defined in exception types.
- Diag(OwnedDecl->getLocation(), diag::err_type_defined_in_param_type)
- << Context.getTypeDeclType(OwnedDecl);
- }
VarDecl *New = BuildObjCExceptionDecl(TInfo, ExceptionType,
D.getSourceRange().getBegin(),
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 0549e9499560..5efc36559d97 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -87,7 +87,7 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
if (FD->isDeleted()) {
Diag(Loc, diag::err_deleted_function_use);
- Diag(D->getLocation(), diag::note_unavailable_here) << true;
+ Diag(D->getLocation(), diag::note_unavailable_here) << 1 << true;
return true;
}
}
@@ -104,17 +104,20 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
break;
case AR_Unavailable:
- if (Message.empty()) {
- if (!UnknownObjCClass)
- Diag(Loc, diag::err_unavailable) << D->getDeclName();
- else
- Diag(Loc, diag::warn_unavailable_fwdclass_message)
- << D->getDeclName();
+ if (cast<Decl>(CurContext)->getAvailability() != AR_Unavailable) {
+ if (Message.empty()) {
+ if (!UnknownObjCClass)
+ Diag(Loc, diag::err_unavailable) << D->getDeclName();
+ else
+ Diag(Loc, diag::warn_unavailable_fwdclass_message)
+ << D->getDeclName();
+ }
+ else
+ Diag(Loc, diag::err_unavailable_message)
+ << D->getDeclName() << Message;
+ Diag(D->getLocation(), diag::note_unavailable_here)
+ << isa<FunctionDecl>(D) << false;
}
- else
- Diag(Loc, diag::err_unavailable_message)
- << D->getDeclName() << Message;
- Diag(D->getLocation(), diag::note_unavailable_here) << 0;
break;
}
@@ -437,8 +440,12 @@ ExprResult Sema::DefaultArgumentPromotion(Expr *E) {
/// will warn if the resulting type is not a POD type, and rejects ObjC
/// interfaces passed by value.
ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
- FunctionDecl *FDecl) {
- ExprResult ExprRes = DefaultArgumentPromotion(E);
+ FunctionDecl *FDecl) {
+ ExprResult ExprRes = CheckPlaceholderExpr(E);
+ if (ExprRes.isInvalid())
+ return ExprError();
+
+ ExprRes = DefaultArgumentPromotion(E);
if (ExprRes.isInvalid())
return ExprError();
E = ExprRes.take();
@@ -456,7 +463,7 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
<< E->getType() << CT))
return ExprError();
- if (!E->getType()->isPODType()) {
+ if (!E->getType().isPODType(Context)) {
// C++0x [expr.call]p7:
// Passing a potentially-evaluated argument of class type (Clause 9)
// having a non-trivial copy constructor, a non-trivial move constructor,
@@ -471,6 +478,11 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
TrivialEnough = true;
}
}
+
+ if (!TrivialEnough &&
+ getLangOptions().ObjCAutoRefCount &&
+ E->getType()->isObjCLifetimeType())
+ TrivialEnough = true;
if (TrivialEnough) {
// Nothing to diagnose. This is okay.
@@ -1004,7 +1016,6 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) {
// Pass &StringTokLocs[0], StringTokLocs.size() to factory!
return Owned(StringLiteral::Create(Context, Literal.GetString(),
- Literal.GetStringLength(),
Literal.AnyWide, Literal.Pascal, StrTy,
&StringTokLocs[0],
StringTokLocs.size()));
@@ -1271,125 +1282,6 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
return Owned(E);
}
-static ExprResult
-BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow,
- const CXXScopeSpec &SS, FieldDecl *Field,
- DeclAccessPair FoundDecl,
- const DeclarationNameInfo &MemberNameInfo);
-
-ExprResult
-Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
- SourceLocation loc,
- IndirectFieldDecl *indirectField,
- Expr *baseObjectExpr,
- SourceLocation opLoc) {
- // First, build the expression that refers to the base object.
-
- bool baseObjectIsPointer = false;
- Qualifiers baseQuals;
-
- // Case 1: the base of the indirect field is not a field.
- VarDecl *baseVariable = indirectField->getVarDecl();
- CXXScopeSpec EmptySS;
- if (baseVariable) {
- assert(baseVariable->getType()->isRecordType());
-
- // In principle we could have a member access expression that
- // accesses an anonymous struct/union that's a static member of
- // the base object's class. However, under the current standard,
- // static data members cannot be anonymous structs or unions.
- // Supporting this is as easy as building a MemberExpr here.
- assert(!baseObjectExpr && "anonymous struct/union is static data member?");
-
- DeclarationNameInfo baseNameInfo(DeclarationName(), loc);
-
- ExprResult result =
- BuildDeclarationNameExpr(EmptySS, baseNameInfo, baseVariable);
- if (result.isInvalid()) return ExprError();
-
- baseObjectExpr = result.take();
- baseObjectIsPointer = false;
- baseQuals = baseObjectExpr->getType().getQualifiers();
-
- // Case 2: the base of the indirect field is a field and the user
- // wrote a member expression.
- } else if (baseObjectExpr) {
- // The caller provided the base object expression. Determine
- // whether its a pointer and whether it adds any qualifiers to the
- // anonymous struct/union fields we're looking into.
- QualType objectType = baseObjectExpr->getType();
-
- if (const PointerType *ptr = objectType->getAs<PointerType>()) {
- baseObjectIsPointer = true;
- objectType = ptr->getPointeeType();
- } else {
- baseObjectIsPointer = false;
- }
- baseQuals = objectType.getQualifiers();
-
- // Case 3: the base of the indirect field is a field and we should
- // build an implicit member access.
- } else {
- // We've found a member of an anonymous struct/union that is
- // inside a non-anonymous struct/union, so in a well-formed
- // program our base object expression is "this".
- QualType ThisTy = getAndCaptureCurrentThisType();
- if (ThisTy.isNull()) {
- Diag(loc, diag::err_invalid_member_use_in_static_method)
- << indirectField->getDeclName();
- return ExprError();
- }
-
- // Our base object expression is "this".
- baseObjectExpr =
- new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/ true);
- baseObjectIsPointer = true;
- baseQuals = ThisTy->castAs<PointerType>()->getPointeeType().getQualifiers();
- }
-
- // Build the implicit member references to the field of the
- // anonymous struct/union.
- Expr *result = baseObjectExpr;
- IndirectFieldDecl::chain_iterator
- FI = indirectField->chain_begin(), FEnd = indirectField->chain_end();
-
- // Build the first member access in the chain with full information.
- if (!baseVariable) {
- FieldDecl *field = cast<FieldDecl>(*FI);
-
- // FIXME: use the real found-decl info!
- DeclAccessPair foundDecl = DeclAccessPair::make(field, field->getAccess());
-
- // Make a nameInfo that properly uses the anonymous name.
- DeclarationNameInfo memberNameInfo(field->getDeclName(), loc);
-
- result = BuildFieldReferenceExpr(*this, result, baseObjectIsPointer,
- EmptySS, field, foundDecl,
- memberNameInfo).take();
- baseObjectIsPointer = false;
-
- // FIXME: check qualified member access
- }
-
- // In all cases, we should now skip the first declaration in the chain.
- ++FI;
-
- while (FI != FEnd) {
- FieldDecl *field = cast<FieldDecl>(*FI++);
-
- // FIXME: these are somewhat meaningless
- DeclarationNameInfo memberNameInfo(field->getDeclName(), loc);
- DeclAccessPair foundDecl = DeclAccessPair::make(field, field->getAccess());
-
- result = BuildFieldReferenceExpr(*this, result, /*isarrow*/ false,
- (FI == FEnd? SS : EmptySS), field,
- foundDecl, memberNameInfo)
- .take();
- }
-
- return Owned(result);
-}
-
/// Decomposes the given name into a DeclarationNameInfo, its location, and
/// possibly a list of template arguments.
///
@@ -1399,215 +1291,30 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
/// This actually loses a lot of source location information for
/// non-standard name kinds; we should consider preserving that in
/// some way.
-static void DecomposeUnqualifiedId(Sema &SemaRef,
- const UnqualifiedId &Id,
- TemplateArgumentListInfo &Buffer,
- DeclarationNameInfo &NameInfo,
- const TemplateArgumentListInfo *&TemplateArgs) {
+void Sema::DecomposeUnqualifiedId(const UnqualifiedId &Id,
+ TemplateArgumentListInfo &Buffer,
+ DeclarationNameInfo &NameInfo,
+ const TemplateArgumentListInfo *&TemplateArgs) {
if (Id.getKind() == UnqualifiedId::IK_TemplateId) {
Buffer.setLAngleLoc(Id.TemplateId->LAngleLoc);
Buffer.setRAngleLoc(Id.TemplateId->RAngleLoc);
- ASTTemplateArgsPtr TemplateArgsPtr(SemaRef,
+ ASTTemplateArgsPtr TemplateArgsPtr(*this,
Id.TemplateId->getTemplateArgs(),
Id.TemplateId->NumArgs);
- SemaRef.translateTemplateArguments(TemplateArgsPtr, Buffer);
+ translateTemplateArguments(TemplateArgsPtr, Buffer);
TemplateArgsPtr.release();
TemplateName TName = Id.TemplateId->Template.get();
SourceLocation TNameLoc = Id.TemplateId->TemplateNameLoc;
- NameInfo = SemaRef.Context.getNameForTemplate(TName, TNameLoc);
+ NameInfo = Context.getNameForTemplate(TName, TNameLoc);
TemplateArgs = &Buffer;
} else {
- NameInfo = SemaRef.GetNameFromUnqualifiedId(Id);
+ NameInfo = GetNameFromUnqualifiedId(Id);
TemplateArgs = 0;
}
}
-/// Determines if the given class is provably not derived from all of
-/// the prospective base classes.
-static bool IsProvablyNotDerivedFrom(Sema &SemaRef,
- CXXRecordDecl *Record,
- const llvm::SmallPtrSet<CXXRecordDecl*, 4> &Bases) {
- if (Bases.count(Record->getCanonicalDecl()))
- return false;
-
- RecordDecl *RD = Record->getDefinition();
- if (!RD) return false;
- Record = cast<CXXRecordDecl>(RD);
-
- for (CXXRecordDecl::base_class_iterator I = Record->bases_begin(),
- E = Record->bases_end(); I != E; ++I) {
- CanQualType BaseT = SemaRef.Context.getCanonicalType((*I).getType());
- CanQual<RecordType> BaseRT = BaseT->getAs<RecordType>();
- if (!BaseRT) return false;
-
- CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(BaseRT->getDecl());
- if (!IsProvablyNotDerivedFrom(SemaRef, BaseRecord, Bases))
- return false;
- }
-
- return true;
-}
-
-enum IMAKind {
- /// The reference is definitely not an instance member access.
- IMA_Static,
-
- /// The reference may be an implicit instance member access.
- IMA_Mixed,
-
- /// The reference may be to an instance member, but it is invalid if
- /// so, because the context is not an instance method.
- IMA_Mixed_StaticContext,
-
- /// The reference may be to an instance member, but it is invalid if
- /// so, because the context is from an unrelated class.
- IMA_Mixed_Unrelated,
-
- /// The reference is definitely an implicit instance member access.
- IMA_Instance,
-
- /// The reference may be to an unresolved using declaration.
- IMA_Unresolved,
-
- /// The reference may be to an unresolved using declaration and the
- /// context is not an instance method.
- IMA_Unresolved_StaticContext,
-
- /// All possible referrents are instance members and the current
- /// context is not an instance method.
- IMA_Error_StaticContext,
-
- /// All possible referrents are instance members of an unrelated
- /// class.
- IMA_Error_Unrelated
-};
-
-/// The given lookup names class member(s) and is not being used for
-/// an address-of-member expression. Classify the type of access
-/// according to whether it's possible that this reference names an
-/// instance member. This is best-effort; it is okay to
-/// conservatively answer "yes", in which case some errors will simply
-/// not be caught until template-instantiation.
-static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
- Scope *CurScope,
- const LookupResult &R) {
- assert(!R.empty() && (*R.begin())->isCXXClassMember());
-
- DeclContext *DC = SemaRef.getFunctionLevelDeclContext();
-
- bool isStaticContext =
- (!isa<CXXMethodDecl>(DC) ||
- cast<CXXMethodDecl>(DC)->isStatic());
-
- // C++0x [expr.prim]p4:
- // Otherwise, if a member-declarator declares a non-static data member
- // of a class X, the expression this is a prvalue of type "pointer to X"
- // within the optional brace-or-equal-initializer.
- if (CurScope->getFlags() & Scope::ThisScope)
- isStaticContext = false;
-
- if (R.isUnresolvableResult())
- return isStaticContext ? IMA_Unresolved_StaticContext : IMA_Unresolved;
-
- // Collect all the declaring classes of instance members we find.
- bool hasNonInstance = false;
- bool hasField = false;
- llvm::SmallPtrSet<CXXRecordDecl*, 4> Classes;
- for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
- NamedDecl *D = *I;
-
- if (D->isCXXInstanceMember()) {
- if (dyn_cast<FieldDecl>(D))
- hasField = true;
-
- CXXRecordDecl *R = cast<CXXRecordDecl>(D->getDeclContext());
- Classes.insert(R->getCanonicalDecl());
- }
- else
- hasNonInstance = true;
- }
-
- // If we didn't find any instance members, it can't be an implicit
- // member reference.
- if (Classes.empty())
- return IMA_Static;
-
- // If the current context is not an instance method, it can't be
- // an implicit member reference.
- if (isStaticContext) {
- if (hasNonInstance)
- return IMA_Mixed_StaticContext;
-
- if (SemaRef.getLangOptions().CPlusPlus0x && hasField) {
- // C++0x [expr.prim.general]p10:
- // An id-expression that denotes a non-static data member or non-static
- // member function of a class can only be used:
- // (...)
- // - if that id-expression denotes a non-static data member and it appears in an unevaluated operand.
- const Sema::ExpressionEvaluationContextRecord& record = SemaRef.ExprEvalContexts.back();
- bool isUnevaluatedExpression = record.Context == Sema::Unevaluated;
- if (isUnevaluatedExpression)
- return IMA_Mixed_StaticContext;
- }
-
- return IMA_Error_StaticContext;
- }
-
- CXXRecordDecl *contextClass;
- if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC))
- contextClass = MD->getParent()->getCanonicalDecl();
- else
- contextClass = cast<CXXRecordDecl>(DC);
-
- // [class.mfct.non-static]p3:
- // ...is used in the body of a non-static member function of class X,
- // if name lookup (3.4.1) resolves the name in the id-expression to a
- // non-static non-type member of some class C [...]
- // ...if C is not X or a base class of X, the class member access expression
- // is ill-formed.
- if (R.getNamingClass() &&
- contextClass != R.getNamingClass()->getCanonicalDecl() &&
- contextClass->isProvablyNotDerivedFrom(R.getNamingClass()))
- return (hasNonInstance ? IMA_Mixed_Unrelated : IMA_Error_Unrelated);
-
- // If we can prove that the current context is unrelated to all the
- // declaring classes, it can't be an implicit member reference (in
- // which case it's an error if any of those members are selected).
- if (IsProvablyNotDerivedFrom(SemaRef, contextClass, Classes))
- return (hasNonInstance ? IMA_Mixed_Unrelated : IMA_Error_Unrelated);
-
- return (hasNonInstance ? IMA_Mixed : IMA_Instance);
-}
-
-/// Diagnose a reference to a field with no object available.
-static void DiagnoseInstanceReference(Sema &SemaRef,
- const CXXScopeSpec &SS,
- NamedDecl *rep,
- const DeclarationNameInfo &nameInfo) {
- SourceLocation Loc = nameInfo.getLoc();
- SourceRange Range(Loc);
- if (SS.isSet()) Range.setBegin(SS.getRange().getBegin());
-
- if (isa<FieldDecl>(rep) || isa<IndirectFieldDecl>(rep)) {
- if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(SemaRef.CurContext)) {
- if (MD->isStatic()) {
- // "invalid use of member 'x' in static member function"
- SemaRef.Diag(Loc, diag::err_invalid_member_use_in_static_method)
- << Range << nameInfo.getName();
- return;
- }
- }
-
- SemaRef.Diag(Loc, diag::err_invalid_non_static_member_use)
- << nameInfo.getName() << Range;
- return;
- }
-
- SemaRef.Diag(Loc, diag::err_member_call_without_object) << Range;
-}
-
/// Diagnose an empty lookup.
///
/// \return false if new lookup candidates were found
@@ -1690,39 +1397,43 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
}
// We didn't find anything, so try to correct for a typo.
- DeclarationName Corrected;
- if (S && (Corrected = CorrectTypo(R, S, &SS, 0, false, CTC))) {
- if (!R.empty()) {
- if (isa<ValueDecl>(*R.begin()) || isa<FunctionTemplateDecl>(*R.begin())) {
+ TypoCorrection Corrected;
+ if (S && (Corrected = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(),
+ S, &SS, NULL, false, CTC))) {
+ std::string CorrectedStr(Corrected.getAsString(getLangOptions()));
+ std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOptions()));
+ R.setLookupName(Corrected.getCorrection());
+
+ if (NamedDecl *ND = Corrected.getCorrectionDecl()) {
+ R.addDecl(ND);
+ if (isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND)) {
if (SS.isEmpty())
- Diag(R.getNameLoc(), diagnostic_suggest) << Name << R.getLookupName()
- << FixItHint::CreateReplacement(R.getNameLoc(),
- R.getLookupName().getAsString());
+ Diag(R.getNameLoc(), diagnostic_suggest) << Name << CorrectedQuotedStr
+ << FixItHint::CreateReplacement(R.getNameLoc(), CorrectedStr);
else
Diag(R.getNameLoc(), diag::err_no_member_suggest)
- << Name << computeDeclContext(SS, false) << R.getLookupName()
+ << Name << computeDeclContext(SS, false) << CorrectedQuotedStr
<< SS.getRange()
- << FixItHint::CreateReplacement(R.getNameLoc(),
- R.getLookupName().getAsString());
- if (NamedDecl *ND = R.getAsSingle<NamedDecl>())
+ << FixItHint::CreateReplacement(R.getNameLoc(), CorrectedStr);
+ if (ND)
Diag(ND->getLocation(), diag::note_previous_decl)
- << ND->getDeclName();
+ << CorrectedQuotedStr;
// Tell the callee to try to recover.
return false;
}
- if (isa<TypeDecl>(*R.begin()) || isa<ObjCInterfaceDecl>(*R.begin())) {
+ if (isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND)) {
// FIXME: If we ended up with a typo for a type name or
// Objective-C class name, we're in trouble because the parser
// is in the wrong place to recover. Suggest the typo
// correction, but don't make it a fix-it since we're not going
// to recover well anyway.
if (SS.isEmpty())
- Diag(R.getNameLoc(), diagnostic_suggest) << Name << R.getLookupName();
+ Diag(R.getNameLoc(), diagnostic_suggest) << Name << CorrectedQuotedStr;
else
Diag(R.getNameLoc(), diag::err_no_member_suggest)
- << Name << computeDeclContext(SS, false) << R.getLookupName()
+ << Name << computeDeclContext(SS, false) << CorrectedQuotedStr
<< SS.getRange();
// Don't try to recover; it won't work.
@@ -1732,15 +1443,15 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
// FIXME: We found a keyword. Suggest it, but don't provide a fix-it
// because we aren't able to recover.
if (SS.isEmpty())
- Diag(R.getNameLoc(), diagnostic_suggest) << Name << Corrected;
+ Diag(R.getNameLoc(), diagnostic_suggest) << Name << CorrectedQuotedStr;
else
Diag(R.getNameLoc(), diag::err_no_member_suggest)
- << Name << computeDeclContext(SS, false) << Corrected
+ << Name << computeDeclContext(SS, false) << CorrectedQuotedStr
<< SS.getRange();
return true;
}
- R.clear();
}
+ R.clear();
// Emit a special diagnostic for failed member lookups.
// FIXME: computing the declaration context might fail here (?)
@@ -1856,7 +1567,7 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
// Decompose the UnqualifiedId into the following data.
DeclarationNameInfo NameInfo;
const TemplateArgumentListInfo *TemplateArgs;
- DecomposeUnqualifiedId(*this, Id, TemplateArgsBuffer, NameInfo, TemplateArgs);
+ DecomposeUnqualifiedId(Id, TemplateArgsBuffer, NameInfo, TemplateArgs);
DeclarationName Name = NameInfo.getName();
IdentifierInfo *II = Name.getAsIdentifierInfo();
@@ -1892,7 +1603,9 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
bool IvarLookupFollowUp = false;
// Perform the required lookup.
- LookupResult R(*this, NameInfo, LookupOrdinaryName);
+ LookupResult R(*this, NameInfo,
+ (Id.getKind() == UnqualifiedId::IK_ImplicitSelfParam)
+ ? LookupObjCImplicitSelfParam : LookupOrdinaryName);
if (TemplateArgs) {
// Lookup the template name again to correctly establish the context in
// which it was found. This is really unfortunate as we already did the
@@ -2032,38 +1745,6 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
return BuildDeclarationNameExpr(SS, R, ADL);
}
-/// Builds an expression which might be an implicit member expression.
-ExprResult
-Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS,
- LookupResult &R,
- const TemplateArgumentListInfo *TemplateArgs) {
- switch (ClassifyImplicitMemberAccess(*this, CurScope, R)) {
- case IMA_Instance:
- return BuildImplicitMemberExpr(SS, R, TemplateArgs, true);
-
- case IMA_Mixed:
- case IMA_Mixed_Unrelated:
- case IMA_Unresolved:
- return BuildImplicitMemberExpr(SS, R, TemplateArgs, false);
-
- case IMA_Static:
- case IMA_Mixed_StaticContext:
- case IMA_Unresolved_StaticContext:
- if (TemplateArgs)
- return BuildTemplateIdExpr(SS, R, false, *TemplateArgs);
- return BuildDeclarationNameExpr(SS, R, false);
-
- case IMA_Error_StaticContext:
- case IMA_Error_Unrelated:
- DiagnoseInstanceReference(*this, SS, R.getRepresentativeDecl(),
- R.getLookupNameInfo());
- return ExprError();
- }
-
- llvm_unreachable("unexpected instance member access kind");
- return ExprError();
-}
-
/// BuildQualifiedDeclarationNameExpr - Build a C++ qualified
/// declaration name, generally during template instantiation.
/// There's a large number of things which don't need to be done along
@@ -2155,6 +1836,7 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
IdentifierInfo &II = Context.Idents.get("self");
UnqualifiedId SelfName;
SelfName.setIdentifier(&II, SourceLocation());
+ SelfName.setKind(UnqualifiedId::IK_ImplicitSelfParam);
CXXScopeSpec SelfScopeSpec;
ExprResult SelfExpr = ActOnIdExpression(S, SelfScopeSpec,
SelfName, false, false);
@@ -2166,27 +1848,6 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
return ExprError();
MarkDeclarationReferenced(Loc, IV);
- Expr *base = SelfExpr.take();
- base = base->IgnoreParenImpCasts();
- if (const DeclRefExpr *DE = dyn_cast<DeclRefExpr>(base)) {
- const NamedDecl *ND = DE->getDecl();
- if (!isa<ImplicitParamDecl>(ND)) {
- // relax the rule such that it is allowed to have a shadow 'self'
- // where stand-alone ivar can be found in this 'self' object.
- // This is to match gcc's behavior.
- ObjCInterfaceDecl *selfIFace = 0;
- if (const ObjCObjectPointerType *OPT =
- base->getType()->getAsObjCInterfacePointerType())
- selfIFace = OPT->getInterfaceDecl();
- if (!selfIFace ||
- !selfIFace->lookupInstanceVariable(IV->getIdentifier())) {
- Diag(Loc, diag::error_implicit_ivar_access)
- << IV->getDeclName();
- Diag(ND->getLocation(), diag::note_declared_at);
- return ExprError();
- }
- }
- }
return Owned(new (Context)
ObjCIvarRefExpr(IV, IV->getType(), Loc,
SelfExpr.take(), true, true));
@@ -2385,120 +2046,6 @@ Sema::PerformObjectMemberConversion(Expr *From,
VK, &BasePath);
}
-/// \brief Build a MemberExpr AST node.
-static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow,
- const CXXScopeSpec &SS, ValueDecl *Member,
- DeclAccessPair FoundDecl,
- const DeclarationNameInfo &MemberNameInfo,
- QualType Ty,
- ExprValueKind VK, ExprObjectKind OK,
- const TemplateArgumentListInfo *TemplateArgs = 0) {
- return MemberExpr::Create(C, Base, isArrow, SS.getWithLocInContext(C),
- Member, FoundDecl, MemberNameInfo,
- TemplateArgs, Ty, VK, OK);
-}
-
-static ExprResult
-BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow,
- const CXXScopeSpec &SS, FieldDecl *Field,
- DeclAccessPair FoundDecl,
- const DeclarationNameInfo &MemberNameInfo) {
- // x.a is an l-value if 'a' has a reference type. Otherwise:
- // x.a is an l-value/x-value/pr-value if the base is (and note
- // that *x is always an l-value), except that if the base isn't
- // an ordinary object then we must have an rvalue.
- ExprValueKind VK = VK_LValue;
- ExprObjectKind OK = OK_Ordinary;
- if (!IsArrow) {
- if (BaseExpr->getObjectKind() == OK_Ordinary)
- VK = BaseExpr->getValueKind();
- else
- VK = VK_RValue;
- }
- if (VK != VK_RValue && Field->isBitField())
- OK = OK_BitField;
-
- // Figure out the type of the member; see C99 6.5.2.3p3, C++ [expr.ref]
- QualType MemberType = Field->getType();
- if (const ReferenceType *Ref = MemberType->getAs<ReferenceType>()) {
- MemberType = Ref->getPointeeType();
- VK = VK_LValue;
- } else {
- QualType BaseType = BaseExpr->getType();
- if (IsArrow) BaseType = BaseType->getAs<PointerType>()->getPointeeType();
-
- Qualifiers BaseQuals = BaseType.getQualifiers();
-
- // GC attributes are never picked up by members.
- BaseQuals.removeObjCGCAttr();
-
- // CVR attributes from the base are picked up by members,
- // except that 'mutable' members don't pick up 'const'.
- if (Field->isMutable()) BaseQuals.removeConst();
-
- Qualifiers MemberQuals
- = S.Context.getCanonicalType(MemberType).getQualifiers();
-
- // TR 18037 does not allow fields to be declared with address spaces.
- assert(!MemberQuals.hasAddressSpace());
-
- Qualifiers Combined = BaseQuals + MemberQuals;
- if (Combined != MemberQuals)
- MemberType = S.Context.getQualifiedType(MemberType, Combined);
- }
-
- S.MarkDeclarationReferenced(MemberNameInfo.getLoc(), Field);
- ExprResult Base =
- S.PerformObjectMemberConversion(BaseExpr, SS.getScopeRep(),
- FoundDecl, Field);
- if (Base.isInvalid())
- return ExprError();
- return S.Owned(BuildMemberExpr(S.Context, Base.take(), IsArrow, SS,
- Field, FoundDecl, MemberNameInfo,
- MemberType, VK, OK));
-}
-
-/// Builds an implicit member access expression. The current context
-/// is known to be an instance method, and the given unqualified lookup
-/// set is known to contain only instance members, at least one of which
-/// is from an appropriate type.
-ExprResult
-Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS,
- LookupResult &R,
- const TemplateArgumentListInfo *TemplateArgs,
- bool IsKnownInstance) {
- assert(!R.empty() && !R.isAmbiguous());
-
- SourceLocation loc = R.getNameLoc();
-
- // We may have found a field within an anonymous union or struct
- // (C++ [class.union]).
- // FIXME: template-ids inside anonymous structs?
- if (IndirectFieldDecl *FD = R.getAsSingle<IndirectFieldDecl>())
- return BuildAnonymousStructUnionMemberReference(SS, R.getNameLoc(), FD);
-
- // If this is known to be an instance access, go ahead and build an
- // implicit 'this' expression now.
- // 'this' expression now.
- QualType ThisTy = getAndCaptureCurrentThisType();
- assert(!ThisTy.isNull() && "didn't correctly pre-flight capture of 'this'");
-
- Expr *baseExpr = 0; // null signifies implicit access
- if (IsKnownInstance) {
- SourceLocation Loc = R.getNameLoc();
- if (SS.getRange().isValid())
- Loc = SS.getRange().getBegin();
- baseExpr = new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/true);
- }
-
- return BuildMemberReferenceExpr(baseExpr, ThisTy,
- /*OpLoc*/ SourceLocation(),
- /*IsArrow*/ true,
- SS,
- /*FirstQualifierInScope*/ 0,
- R, TemplateArgs);
-}
-
bool Sema::UseArgumentDependentLookup(const CXXScopeSpec &SS,
const LookupResult &R,
bool HasTrailingLParen) {
@@ -3160,6 +2707,20 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *Op,
Op->getSourceRange(), ExprKind))
return true;
+ if (ExprKind == UETT_SizeOf) {
+ if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(Op->IgnoreParens())) {
+ if (ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(DeclRef->getFoundDecl())) {
+ QualType OType = PVD->getOriginalType();
+ QualType Type = PVD->getType();
+ if (Type->isPointerType() && OType->isArrayType()) {
+ Diag(Op->getExprLoc(), diag::warn_sizeof_array_param)
+ << Type << OType;
+ Diag(PVD->getLocation(), diag::note_declared_at);
+ }
+ }
+ }
+ }
+
return false;
}
@@ -3274,6 +2835,12 @@ Sema::CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo,
ExprResult
Sema::CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc,
UnaryExprOrTypeTrait ExprKind) {
+ ExprResult PE = CheckPlaceholderExpr(E);
+ if (PE.isInvalid())
+ return ExprError();
+
+ E = PE.get();
+
// Verify that the operand is valid.
bool isInvalid = false;
if (E->isTypeDependent()) {
@@ -3285,10 +2852,6 @@ Sema::CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc,
} else if (E->getBitField()) { // C99 6.5.3.4p1.
Diag(E->getExprLoc(), diag::err_sizeof_alignof_bitfield) << 0;
isInvalid = true;
- } else if (E->getType()->isPlaceholderType()) {
- ExprResult PE = CheckPlaceholderExpr(E);
- if (PE.isInvalid()) return ExprError();
- return CreateUnaryExprOrTypeTraitExpr(PE.take(), OpLoc, ExprKind);
} else {
isInvalid = CheckUnaryExprOrTypeTraitOperand(E, UETT_SizeOf);
}
@@ -3372,19 +2935,6 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
return BuildUnaryOp(S, OpLoc, Opc, Input);
}
-/// Expressions of certain arbitrary types are forbidden by C from
-/// having l-value type. These 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.
-static bool IsCForbiddenLValueType(ASTContext &C, QualType T) {
- return ((T->isVoidType() && !T.hasQualifiers()) ||
- T->isFunctionType());
-}
-
ExprResult
Sema::ActOnArraySubscriptExpr(Scope *S, Expr *Base, SourceLocation LLoc,
Expr *Idx, SourceLocation RLoc) {
@@ -3528,7 +3078,7 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
if (ResultType->isVoidType() && !getLangOptions().CPlusPlus) {
// GNU extension: subscripting on pointer to void
- Diag(LLoc, diag::ext_gnu_void_ptr)
+ Diag(LLoc, diag::ext_gnu_subscript_void_type)
<< BaseExpr->getSourceRange();
// C forbids expressions of unqualified void type from being l-values.
@@ -3548,1109 +3098,12 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
}
assert(VK == VK_RValue || LangOpts.CPlusPlus ||
- !IsCForbiddenLValueType(Context, ResultType));
+ !ResultType.isCForbiddenLValueType());
return Owned(new (Context) ArraySubscriptExpr(LHSExp, RHSExp,
ResultType, VK, OK, RLoc));
}
-/// Check an ext-vector component access expression.
-///
-/// VK should be set in advance to the value kind of the base
-/// expression.
-static QualType
-CheckExtVectorComponent(Sema &S, QualType baseType, ExprValueKind &VK,
- SourceLocation OpLoc, const IdentifierInfo *CompName,
- SourceLocation CompLoc) {
- // FIXME: Share logic with ExtVectorElementExpr::containsDuplicateElements,
- // see FIXME there.
- //
- // FIXME: This logic can be greatly simplified by splitting it along
- // halving/not halving and reworking the component checking.
- const ExtVectorType *vecType = baseType->getAs<ExtVectorType>();
-
- // The vector accessor can't exceed the number of elements.
- const char *compStr = CompName->getNameStart();
-
- // This flag determines whether or not the component is one of the four
- // special names that indicate a subset of exactly half the elements are
- // to be selected.
- bool HalvingSwizzle = false;
-
- // This flag determines whether or not CompName has an 's' char prefix,
- // indicating that it is a string of hex values to be used as vector indices.
- bool HexSwizzle = *compStr == 's' || *compStr == 'S';
-
- bool HasRepeated = false;
- bool HasIndex[16] = {};
-
- int Idx;
-
- // Check that we've found one of the special components, or that the component
- // names must come from the same set.
- if (!strcmp(compStr, "hi") || !strcmp(compStr, "lo") ||
- !strcmp(compStr, "even") || !strcmp(compStr, "odd")) {
- HalvingSwizzle = true;
- } else if (!HexSwizzle &&
- (Idx = vecType->getPointAccessorIdx(*compStr)) != -1) {
- do {
- if (HasIndex[Idx]) HasRepeated = true;
- HasIndex[Idx] = true;
- compStr++;
- } while (*compStr && (Idx = vecType->getPointAccessorIdx(*compStr)) != -1);
- } else {
- if (HexSwizzle) compStr++;
- while ((Idx = vecType->getNumericAccessorIdx(*compStr)) != -1) {
- if (HasIndex[Idx]) HasRepeated = true;
- HasIndex[Idx] = true;
- compStr++;
- }
- }
-
- if (!HalvingSwizzle && *compStr) {
- // We didn't get to the end of the string. This means the component names
- // didn't come from the same set *or* we encountered an illegal name.
- S.Diag(OpLoc, diag::err_ext_vector_component_name_illegal)
- << llvm::StringRef(compStr, 1) << SourceRange(CompLoc);
- return QualType();
- }
-
- // Ensure no component accessor exceeds the width of the vector type it
- // operates on.
- if (!HalvingSwizzle) {
- compStr = CompName->getNameStart();
-
- if (HexSwizzle)
- compStr++;
-
- while (*compStr) {
- if (!vecType->isAccessorWithinNumElements(*compStr++)) {
- S.Diag(OpLoc, diag::err_ext_vector_component_exceeds_length)
- << baseType << SourceRange(CompLoc);
- return QualType();
- }
- }
- }
-
- // The component accessor looks fine - now we need to compute the actual type.
- // The vector type is implied by the component accessor. For example,
- // vec4.b is a float, vec4.xy is a vec2, vec4.rgb is a vec3, etc.
- // vec4.s0 is a float, vec4.s23 is a vec3, etc.
- // vec4.hi, vec4.lo, vec4.e, and vec4.o all return vec2.
- unsigned CompSize = HalvingSwizzle ? (vecType->getNumElements() + 1) / 2
- : CompName->getLength();
- if (HexSwizzle)
- CompSize--;
-
- if (CompSize == 1)
- return vecType->getElementType();
-
- if (HasRepeated) VK = VK_RValue;
-
- QualType VT = S.Context.getExtVectorType(vecType->getElementType(), CompSize);
- // Now look up the TypeDefDecl from the vector type. Without this,
- // diagostics look bad. We want extended vector types to appear built-in.
- for (unsigned i = 0, E = S.ExtVectorDecls.size(); i != E; ++i) {
- if (S.ExtVectorDecls[i]->getUnderlyingType() == VT)
- return S.Context.getTypedefType(S.ExtVectorDecls[i]);
- }
- return VT; // should never get here (a typedef type should always be found).
-}
-
-static Decl *FindGetterSetterNameDeclFromProtocolList(const ObjCProtocolDecl*PDecl,
- IdentifierInfo *Member,
- const Selector &Sel,
- ASTContext &Context) {
- if (Member)
- if (ObjCPropertyDecl *PD = PDecl->FindPropertyDeclaration(Member))
- return PD;
- if (ObjCMethodDecl *OMD = PDecl->getInstanceMethod(Sel))
- return OMD;
-
- for (ObjCProtocolDecl::protocol_iterator I = PDecl->protocol_begin(),
- E = PDecl->protocol_end(); I != E; ++I) {
- if (Decl *D = FindGetterSetterNameDeclFromProtocolList(*I, Member, Sel,
- Context))
- return D;
- }
- return 0;
-}
-
-static Decl *FindGetterSetterNameDecl(const ObjCObjectPointerType *QIdTy,
- IdentifierInfo *Member,
- const Selector &Sel,
- ASTContext &Context) {
- // Check protocols on qualified interfaces.
- Decl *GDecl = 0;
- for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(),
- E = QIdTy->qual_end(); I != E; ++I) {
- if (Member)
- if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Member)) {
- GDecl = PD;
- break;
- }
- // Also must look for a getter or setter name which uses property syntax.
- if (ObjCMethodDecl *OMD = (*I)->getInstanceMethod(Sel)) {
- GDecl = OMD;
- break;
- }
- }
- if (!GDecl) {
- for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(),
- E = QIdTy->qual_end(); I != E; ++I) {
- // Search in the protocol-qualifier list of current protocol.
- GDecl = FindGetterSetterNameDeclFromProtocolList(*I, Member, Sel,
- Context);
- if (GDecl)
- return GDecl;
- }
- }
- return GDecl;
-}
-
-ExprResult
-Sema::ActOnDependentMemberExpr(Expr *BaseExpr, QualType BaseType,
- bool IsArrow, SourceLocation OpLoc,
- const CXXScopeSpec &SS,
- NamedDecl *FirstQualifierInScope,
- const DeclarationNameInfo &NameInfo,
- const TemplateArgumentListInfo *TemplateArgs) {
- // Even in dependent contexts, try to diagnose base expressions with
- // obviously wrong types, e.g.:
- //
- // T* t;
- // t.f;
- //
- // In Obj-C++, however, the above expression is valid, since it could be
- // accessing the 'f' property if T is an Obj-C interface. The extra check
- // allows this, while still reporting an error if T is a struct pointer.
- if (!IsArrow) {
- const PointerType *PT = BaseType->getAs<PointerType>();
- if (PT && (!getLangOptions().ObjC1 ||
- PT->getPointeeType()->isRecordType())) {
- assert(BaseExpr && "cannot happen with implicit member accesses");
- Diag(NameInfo.getLoc(), diag::err_typecheck_member_reference_struct_union)
- << BaseType << BaseExpr->getSourceRange();
- return ExprError();
- }
- }
-
- assert(BaseType->isDependentType() ||
- NameInfo.getName().isDependentName() ||
- isDependentScopeSpecifier(SS));
-
- // Get the type being accessed in BaseType. If this is an arrow, the BaseExpr
- // must have pointer type, and the accessed type is the pointee.
- return Owned(CXXDependentScopeMemberExpr::Create(Context, BaseExpr, BaseType,
- IsArrow, OpLoc,
- SS.getWithLocInContext(Context),
- FirstQualifierInScope,
- NameInfo, TemplateArgs));
-}
-
-/// We know that the given qualified member reference points only to
-/// declarations which do not belong to the static type of the base
-/// expression. Diagnose the problem.
-static void DiagnoseQualifiedMemberReference(Sema &SemaRef,
- Expr *BaseExpr,
- QualType BaseType,
- const CXXScopeSpec &SS,
- NamedDecl *rep,
- const DeclarationNameInfo &nameInfo) {
- // If this is an implicit member access, use a different set of
- // diagnostics.
- if (!BaseExpr)
- return DiagnoseInstanceReference(SemaRef, SS, rep, nameInfo);
-
- SemaRef.Diag(nameInfo.getLoc(), diag::err_qualified_member_of_unrelated)
- << SS.getRange() << rep << BaseType;
-}
-
-// Check whether the declarations we found through a nested-name
-// specifier in a member expression are actually members of the base
-// type. The restriction here is:
-//
-// C++ [expr.ref]p2:
-// ... In these cases, the id-expression shall name a
-// member of the class or of one of its base classes.
-//
-// So it's perfectly legitimate for the nested-name specifier to name
-// an unrelated class, and for us to find an overload set including
-// decls from classes which are not superclasses, as long as the decl
-// we actually pick through overload resolution is from a superclass.
-bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr,
- QualType BaseType,
- const CXXScopeSpec &SS,
- const LookupResult &R) {
- const RecordType *BaseRT = BaseType->getAs<RecordType>();
- if (!BaseRT) {
- // We can't check this yet because the base type is still
- // dependent.
- assert(BaseType->isDependentType());
- return false;
- }
- CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(BaseRT->getDecl());
-
- for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
- // If this is an implicit member reference and we find a
- // non-instance member, it's not an error.
- if (!BaseExpr && !(*I)->isCXXInstanceMember())
- return false;
-
- // Note that we use the DC of the decl, not the underlying decl.
- DeclContext *DC = (*I)->getDeclContext();
- while (DC->isTransparentContext())
- DC = DC->getParent();
-
- if (!DC->isRecord())
- continue;
-
- llvm::SmallPtrSet<CXXRecordDecl*,4> MemberRecord;
- MemberRecord.insert(cast<CXXRecordDecl>(DC)->getCanonicalDecl());
-
- if (!IsProvablyNotDerivedFrom(*this, BaseRecord, MemberRecord))
- return false;
- }
-
- DiagnoseQualifiedMemberReference(*this, BaseExpr, BaseType, SS,
- R.getRepresentativeDecl(),
- R.getLookupNameInfo());
- return true;
-}
-
-static bool
-LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
- SourceRange BaseRange, const RecordType *RTy,
- SourceLocation OpLoc, CXXScopeSpec &SS,
- bool HasTemplateArgs) {
- RecordDecl *RDecl = RTy->getDecl();
- if (SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0),
- SemaRef.PDiag(diag::err_typecheck_incomplete_tag)
- << BaseRange))
- return true;
-
- if (HasTemplateArgs) {
- // LookupTemplateName doesn't expect these both to exist simultaneously.
- QualType ObjectType = SS.isSet() ? QualType() : QualType(RTy, 0);
-
- bool MOUS;
- SemaRef.LookupTemplateName(R, 0, SS, ObjectType, false, MOUS);
- return false;
- }
-
- DeclContext *DC = RDecl;
- if (SS.isSet()) {
- // If the member name was a qualified-id, look into the
- // nested-name-specifier.
- DC = SemaRef.computeDeclContext(SS, false);
-
- if (SemaRef.RequireCompleteDeclContext(SS, DC)) {
- SemaRef.Diag(SS.getRange().getEnd(), diag::err_typecheck_incomplete_tag)
- << SS.getRange() << DC;
- return true;
- }
-
- assert(DC && "Cannot handle non-computable dependent contexts in lookup");
-
- if (!isa<TypeDecl>(DC)) {
- SemaRef.Diag(R.getNameLoc(), diag::err_qualified_member_nonclass)
- << DC << SS.getRange();
- return true;
- }
- }
-
- // The record definition is complete, now look up the member.
- SemaRef.LookupQualifiedName(R, DC);
-
- if (!R.empty())
- return false;
-
- // We didn't find anything with the given name, so try to correct
- // for typos.
- DeclarationName Name = R.getLookupName();
- if (SemaRef.CorrectTypo(R, 0, &SS, DC, false, Sema::CTC_MemberLookup) &&
- !R.empty() &&
- (isa<ValueDecl>(*R.begin()) || isa<FunctionTemplateDecl>(*R.begin()))) {
- SemaRef.Diag(R.getNameLoc(), diag::err_no_member_suggest)
- << Name << DC << R.getLookupName() << SS.getRange()
- << FixItHint::CreateReplacement(R.getNameLoc(),
- R.getLookupName().getAsString());
- if (NamedDecl *ND = R.getAsSingle<NamedDecl>())
- SemaRef.Diag(ND->getLocation(), diag::note_previous_decl)
- << ND->getDeclName();
- return false;
- } else {
- R.clear();
- R.setLookupName(Name);
- }
-
- return false;
-}
-
-ExprResult
-Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
- SourceLocation OpLoc, bool IsArrow,
- CXXScopeSpec &SS,
- NamedDecl *FirstQualifierInScope,
- const DeclarationNameInfo &NameInfo,
- const TemplateArgumentListInfo *TemplateArgs) {
- if (BaseType->isDependentType() ||
- (SS.isSet() && isDependentScopeSpecifier(SS)))
- return ActOnDependentMemberExpr(Base, BaseType,
- IsArrow, OpLoc,
- SS, FirstQualifierInScope,
- NameInfo, TemplateArgs);
-
- LookupResult R(*this, NameInfo, LookupMemberName);
-
- // Implicit member accesses.
- if (!Base) {
- QualType RecordTy = BaseType;
- if (IsArrow) RecordTy = RecordTy->getAs<PointerType>()->getPointeeType();
- if (LookupMemberExprInRecord(*this, R, SourceRange(),
- RecordTy->getAs<RecordType>(),
- OpLoc, SS, TemplateArgs != 0))
- return ExprError();
-
- // Explicit member accesses.
- } else {
- ExprResult BaseResult = Owned(Base);
- ExprResult Result =
- LookupMemberExpr(R, BaseResult, IsArrow, OpLoc,
- SS, /*ObjCImpDecl*/ 0, TemplateArgs != 0);
-
- if (BaseResult.isInvalid())
- return ExprError();
- Base = BaseResult.take();
-
- if (Result.isInvalid()) {
- Owned(Base);
- return ExprError();
- }
-
- if (Result.get())
- return move(Result);
-
- // LookupMemberExpr can modify Base, and thus change BaseType
- BaseType = Base->getType();
- }
-
- return BuildMemberReferenceExpr(Base, BaseType,
- OpLoc, IsArrow, SS, FirstQualifierInScope,
- R, TemplateArgs);
-}
-
-ExprResult
-Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
- SourceLocation OpLoc, bool IsArrow,
- const CXXScopeSpec &SS,
- NamedDecl *FirstQualifierInScope,
- LookupResult &R,
- const TemplateArgumentListInfo *TemplateArgs,
- bool SuppressQualifierCheck) {
- QualType BaseType = BaseExprType;
- if (IsArrow) {
- assert(BaseType->isPointerType());
- BaseType = BaseType->getAs<PointerType>()->getPointeeType();
- }
- R.setBaseObjectType(BaseType);
-
- const DeclarationNameInfo &MemberNameInfo = R.getLookupNameInfo();
- DeclarationName MemberName = MemberNameInfo.getName();
- SourceLocation MemberLoc = MemberNameInfo.getLoc();
-
- if (R.isAmbiguous())
- return ExprError();
-
- if (R.empty()) {
- // Rederive where we looked up.
- DeclContext *DC = (SS.isSet()
- ? computeDeclContext(SS, false)
- : BaseType->getAs<RecordType>()->getDecl());
-
- Diag(R.getNameLoc(), diag::err_no_member)
- << MemberName << DC
- << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange());
- return ExprError();
- }
-
- // Diagnose lookups that find only declarations from a non-base
- // type. This is possible for either qualified lookups (which may
- // have been qualified with an unrelated type) or implicit member
- // expressions (which were found with unqualified lookup and thus
- // may have come from an enclosing scope). Note that it's okay for
- // lookup to find declarations from a non-base type as long as those
- // aren't the ones picked by overload resolution.
- if ((SS.isSet() || !BaseExpr ||
- (isa<CXXThisExpr>(BaseExpr) &&
- cast<CXXThisExpr>(BaseExpr)->isImplicit())) &&
- !SuppressQualifierCheck &&
- CheckQualifiedMemberReference(BaseExpr, BaseType, SS, R))
- return ExprError();
-
- // Construct an unresolved result if we in fact got an unresolved
- // result.
- if (R.isOverloadedResult() || R.isUnresolvableResult()) {
- // Suppress any lookup-related diagnostics; we'll do these when we
- // pick a member.
- R.suppressDiagnostics();
-
- UnresolvedMemberExpr *MemExpr
- = UnresolvedMemberExpr::Create(Context, R.isUnresolvableResult(),
- BaseExpr, BaseExprType,
- IsArrow, OpLoc,
- SS.getWithLocInContext(Context),
- MemberNameInfo,
- TemplateArgs, R.begin(), R.end());
-
- return Owned(MemExpr);
- }
-
- assert(R.isSingleResult());
- DeclAccessPair FoundDecl = R.begin().getPair();
- NamedDecl *MemberDecl = R.getFoundDecl();
-
- // FIXME: diagnose the presence of template arguments now.
-
- // If the decl being referenced had an error, return an error for this
- // sub-expr without emitting another error, in order to avoid cascading
- // error cases.
- if (MemberDecl->isInvalidDecl())
- return ExprError();
-
- // Handle the implicit-member-access case.
- if (!BaseExpr) {
- // If this is not an instance member, convert to a non-member access.
- if (!MemberDecl->isCXXInstanceMember())
- return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(), MemberDecl);
-
- SourceLocation Loc = R.getNameLoc();
- if (SS.getRange().isValid())
- Loc = SS.getRange().getBegin();
- BaseExpr = new (Context) CXXThisExpr(Loc, BaseExprType,/*isImplicit=*/true);
- }
-
- bool ShouldCheckUse = true;
- if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MemberDecl)) {
- // Don't diagnose the use of a virtual member function unless it's
- // explicitly qualified.
- if (MD->isVirtual() && !SS.isSet())
- ShouldCheckUse = false;
- }
-
- // Check the use of this member.
- if (ShouldCheckUse && DiagnoseUseOfDecl(MemberDecl, MemberLoc)) {
- Owned(BaseExpr);
- return ExprError();
- }
-
- // Perform a property load on the base regardless of whether we
- // actually need it for the declaration.
- if (BaseExpr->getObjectKind() == OK_ObjCProperty) {
- ExprResult Result = ConvertPropertyForRValue(BaseExpr);
- if (Result.isInvalid())
- return ExprError();
- BaseExpr = Result.take();
- }
-
- if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl))
- return BuildFieldReferenceExpr(*this, BaseExpr, IsArrow,
- SS, FD, FoundDecl, MemberNameInfo);
-
- if (IndirectFieldDecl *FD = dyn_cast<IndirectFieldDecl>(MemberDecl))
- // We may have found a field within an anonymous union or struct
- // (C++ [class.union]).
- return BuildAnonymousStructUnionMemberReference(SS, MemberLoc, FD,
- BaseExpr, OpLoc);
-
- if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) {
- MarkDeclarationReferenced(MemberLoc, Var);
- return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS,
- Var, FoundDecl, MemberNameInfo,
- Var->getType().getNonReferenceType(),
- VK_LValue, OK_Ordinary));
- }
-
- if (CXXMethodDecl *MemberFn = dyn_cast<CXXMethodDecl>(MemberDecl)) {
- ExprValueKind valueKind;
- QualType type;
- if (MemberFn->isInstance()) {
- valueKind = VK_RValue;
- type = Context.BoundMemberTy;
- } else {
- valueKind = VK_LValue;
- type = MemberFn->getType();
- }
-
- MarkDeclarationReferenced(MemberLoc, MemberDecl);
- return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS,
- MemberFn, FoundDecl, MemberNameInfo,
- type, valueKind, OK_Ordinary));
- }
- assert(!isa<FunctionDecl>(MemberDecl) && "member function not C++ method?");
-
- if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) {
- MarkDeclarationReferenced(MemberLoc, MemberDecl);
- return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS,
- Enum, FoundDecl, MemberNameInfo,
- Enum->getType(), VK_RValue, OK_Ordinary));
- }
-
- Owned(BaseExpr);
-
- // We found something that we didn't expect. Complain.
- if (isa<TypeDecl>(MemberDecl))
- Diag(MemberLoc, diag::err_typecheck_member_reference_type)
- << MemberName << BaseType << int(IsArrow);
- else
- Diag(MemberLoc, diag::err_typecheck_member_reference_unknown)
- << MemberName << BaseType << int(IsArrow);
-
- Diag(MemberDecl->getLocation(), diag::note_member_declared_here)
- << MemberName;
- R.suppressDiagnostics();
- return ExprError();
-}
-
-/// Given that normal member access failed on the given expression,
-/// and given that the expression's type involves builtin-id or
-/// builtin-Class, decide whether substituting in the redefinition
-/// types would be profitable. The redefinition type is whatever
-/// this translation unit tried to typedef to id/Class; we store
-/// it to the side and then re-use it in places like this.
-static bool ShouldTryAgainWithRedefinitionType(Sema &S, ExprResult &base) {
- const ObjCObjectPointerType *opty
- = base.get()->getType()->getAs<ObjCObjectPointerType>();
- if (!opty) return false;
-
- const ObjCObjectType *ty = opty->getObjectType();
-
- QualType redef;
- if (ty->isObjCId()) {
- redef = S.Context.ObjCIdRedefinitionType;
- } else if (ty->isObjCClass()) {
- redef = S.Context.ObjCClassRedefinitionType;
- } else {
- return false;
- }
-
- // Do the substitution as long as the redefinition type isn't just a
- // possibly-qualified pointer to builtin-id or builtin-Class again.
- opty = redef->getAs<ObjCObjectPointerType>();
- if (opty && !opty->getObjectType()->getInterface() != 0)
- return false;
-
- base = S.ImpCastExprToType(base.take(), redef, CK_BitCast);
- return true;
-}
-
-/// Look up the given member of the given non-type-dependent
-/// expression. This can return in one of two ways:
-/// * If it returns a sentinel null-but-valid result, the caller will
-/// assume that lookup was performed and the results written into
-/// the provided structure. It will take over from there.
-/// * Otherwise, the returned expression will be produced in place of
-/// an ordinary member expression.
-///
-/// The ObjCImpDecl bit is a gross hack that will need to be properly
-/// fixed for ObjC++.
-ExprResult
-Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
- bool &IsArrow, SourceLocation OpLoc,
- CXXScopeSpec &SS,
- Decl *ObjCImpDecl, bool HasTemplateArgs) {
- assert(BaseExpr.get() && "no base expression");
-
- // Perform default conversions.
- BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take());
-
- if (IsArrow) {
- BaseExpr = DefaultLvalueConversion(BaseExpr.take());
- if (BaseExpr.isInvalid())
- return ExprError();
- }
-
- QualType BaseType = BaseExpr.get()->getType();
- assert(!BaseType->isDependentType());
-
- DeclarationName MemberName = R.getLookupName();
- SourceLocation MemberLoc = R.getNameLoc();
-
- // For later type-checking purposes, turn arrow accesses into dot
- // accesses. The only access type we support that doesn't follow
- // the C equivalence "a->b === (*a).b" is ObjC property accesses,
- // and those never use arrows, so this is unaffected.
- if (IsArrow) {
- if (const PointerType *Ptr = BaseType->getAs<PointerType>())
- BaseType = Ptr->getPointeeType();
- else if (const ObjCObjectPointerType *Ptr
- = BaseType->getAs<ObjCObjectPointerType>())
- BaseType = Ptr->getPointeeType();
- else if (BaseType->isRecordType()) {
- // Recover from arrow accesses to records, e.g.:
- // struct MyRecord foo;
- // foo->bar
- // This is actually well-formed in C++ if MyRecord has an
- // overloaded operator->, but that should have been dealt with
- // by now.
- Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
- << BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange()
- << FixItHint::CreateReplacement(OpLoc, ".");
- IsArrow = false;
- } else if (BaseType == Context.BoundMemberTy) {
- goto fail;
- } else {
- Diag(MemberLoc, diag::err_typecheck_member_reference_arrow)
- << BaseType << BaseExpr.get()->getSourceRange();
- return ExprError();
- }
- }
-
- // Handle field access to simple records.
- if (const RecordType *RTy = BaseType->getAs<RecordType>()) {
- if (LookupMemberExprInRecord(*this, R, BaseExpr.get()->getSourceRange(),
- RTy, OpLoc, SS, HasTemplateArgs))
- return ExprError();
-
- // Returning valid-but-null is how we indicate to the caller that
- // the lookup result was filled in.
- return Owned((Expr*) 0);
- }
-
- // Handle ivar access to Objective-C objects.
- if (const ObjCObjectType *OTy = BaseType->getAs<ObjCObjectType>()) {
- IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
-
- // There are three cases for the base type:
- // - builtin id (qualified or unqualified)
- // - builtin Class (qualified or unqualified)
- // - an interface
- ObjCInterfaceDecl *IDecl = OTy->getInterface();
- if (!IDecl) {
- // There's an implicit 'isa' ivar on all objects.
- // But we only actually find it this way on objects of type 'id',
- // apparently.
- if (OTy->isObjCId() && Member->isStr("isa"))
- return Owned(new (Context) ObjCIsaExpr(BaseExpr.take(), IsArrow, MemberLoc,
- Context.getObjCClassType()));
-
- if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr))
- return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
- ObjCImpDecl, HasTemplateArgs);
- goto fail;
- }
-
- ObjCInterfaceDecl *ClassDeclared;
- ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(Member, ClassDeclared);
-
- if (!IV) {
- // Attempt to correct for typos in ivar names.
- LookupResult Res(*this, R.getLookupName(), R.getNameLoc(),
- LookupMemberName);
- if (CorrectTypo(Res, 0, 0, IDecl, false,
- IsArrow ? CTC_ObjCIvarLookup
- : CTC_ObjCPropertyLookup) &&
- (IV = Res.getAsSingle<ObjCIvarDecl>())) {
- Diag(R.getNameLoc(),
- diag::err_typecheck_member_reference_ivar_suggest)
- << IDecl->getDeclName() << MemberName << IV->getDeclName()
- << FixItHint::CreateReplacement(R.getNameLoc(),
- IV->getNameAsString());
- Diag(IV->getLocation(), diag::note_previous_decl)
- << IV->getDeclName();
- } else {
- Res.clear();
- Res.setLookupName(Member);
-
- Diag(MemberLoc, diag::err_typecheck_member_reference_ivar)
- << IDecl->getDeclName() << MemberName
- << BaseExpr.get()->getSourceRange();
- return ExprError();
- }
- }
-
- // If the decl being referenced had an error, return an error for this
- // sub-expr without emitting another error, in order to avoid cascading
- // error cases.
- if (IV->isInvalidDecl())
- return ExprError();
-
- // Check whether we can reference this field.
- if (DiagnoseUseOfDecl(IV, MemberLoc))
- return ExprError();
- if (IV->getAccessControl() != ObjCIvarDecl::Public &&
- IV->getAccessControl() != ObjCIvarDecl::Package) {
- ObjCInterfaceDecl *ClassOfMethodDecl = 0;
- if (ObjCMethodDecl *MD = getCurMethodDecl())
- ClassOfMethodDecl = MD->getClassInterface();
- else if (ObjCImpDecl && getCurFunctionDecl()) {
- // Case of a c-function declared inside an objc implementation.
- // FIXME: For a c-style function nested inside an objc implementation
- // class, there is no implementation context available, so we pass
- // down the context as argument to this routine. Ideally, this context
- // need be passed down in the AST node and somehow calculated from the
- // AST for a function decl.
- if (ObjCImplementationDecl *IMPD =
- dyn_cast<ObjCImplementationDecl>(ObjCImpDecl))
- ClassOfMethodDecl = IMPD->getClassInterface();
- else if (ObjCCategoryImplDecl* CatImplClass =
- dyn_cast<ObjCCategoryImplDecl>(ObjCImpDecl))
- ClassOfMethodDecl = CatImplClass->getClassInterface();
- }
-
- if (IV->getAccessControl() == ObjCIvarDecl::Private) {
- if (ClassDeclared != IDecl ||
- ClassOfMethodDecl != ClassDeclared)
- Diag(MemberLoc, diag::error_private_ivar_access)
- << IV->getDeclName();
- } else if (!IDecl->isSuperClassOf(ClassOfMethodDecl))
- // @protected
- Diag(MemberLoc, diag::error_protected_ivar_access)
- << IV->getDeclName();
- }
-
- return Owned(new (Context) ObjCIvarRefExpr(IV, IV->getType(),
- MemberLoc, BaseExpr.take(),
- IsArrow));
- }
-
- // Objective-C property access.
- const ObjCObjectPointerType *OPT;
- if (!IsArrow && (OPT = BaseType->getAs<ObjCObjectPointerType>())) {
- // This actually uses the base as an r-value.
- BaseExpr = DefaultLvalueConversion(BaseExpr.take());
- if (BaseExpr.isInvalid())
- return ExprError();
-
- assert(Context.hasSameUnqualifiedType(BaseType, BaseExpr.get()->getType()));
-
- IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
-
- const ObjCObjectType *OT = OPT->getObjectType();
-
- // id, with and without qualifiers.
- if (OT->isObjCId()) {
- // Check protocols on qualified interfaces.
- Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
- if (Decl *PMDecl = FindGetterSetterNameDecl(OPT, Member, Sel, Context)) {
- if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(PMDecl)) {
- // Check the use of this declaration
- if (DiagnoseUseOfDecl(PD, MemberLoc))
- return ExprError();
-
- QualType T = PD->getType();
- if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl())
- T = getMessageSendResultType(BaseType, Getter, false, false);
-
- return Owned(new (Context) ObjCPropertyRefExpr(PD, T,
- VK_LValue,
- OK_ObjCProperty,
- MemberLoc,
- BaseExpr.take()));
- }
-
- if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(PMDecl)) {
- // Check the use of this method.
- if (DiagnoseUseOfDecl(OMD, MemberLoc))
- return ExprError();
- Selector SetterSel =
- SelectorTable::constructSetterName(PP.getIdentifierTable(),
- PP.getSelectorTable(), Member);
- ObjCMethodDecl *SMD = 0;
- if (Decl *SDecl = FindGetterSetterNameDecl(OPT, /*Property id*/0,
- SetterSel, Context))
- SMD = dyn_cast<ObjCMethodDecl>(SDecl);
- QualType PType = getMessageSendResultType(BaseType, OMD, false,
- false);
-
- ExprValueKind VK = VK_LValue;
- if (!getLangOptions().CPlusPlus &&
- IsCForbiddenLValueType(Context, PType))
- VK = VK_RValue;
- ExprObjectKind OK = (VK == VK_RValue ? OK_Ordinary : OK_ObjCProperty);
-
- return Owned(new (Context) ObjCPropertyRefExpr(OMD, SMD, PType,
- VK, OK,
- MemberLoc, BaseExpr.take()));
- }
- }
- // Use of id.member can only be for a property reference. Do not
- // use the 'id' redefinition in this case.
- if (IsArrow && ShouldTryAgainWithRedefinitionType(*this, BaseExpr))
- return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
- ObjCImpDecl, HasTemplateArgs);
-
- return ExprError(Diag(MemberLoc, diag::err_property_not_found)
- << MemberName << BaseType);
- }
-
- // 'Class', unqualified only.
- if (OT->isObjCClass()) {
- // Only works in a method declaration (??!).
- ObjCMethodDecl *MD = getCurMethodDecl();
- if (!MD) {
- if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr))
- return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
- ObjCImpDecl, HasTemplateArgs);
-
- goto fail;
- }
-
- // Also must look for a getter name which uses property syntax.
- Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
- ObjCInterfaceDecl *IFace = MD->getClassInterface();
- ObjCMethodDecl *Getter;
- if ((Getter = IFace->lookupClassMethod(Sel))) {
- // Check the use of this method.
- if (DiagnoseUseOfDecl(Getter, MemberLoc))
- return ExprError();
- } else
- Getter = IFace->lookupPrivateMethod(Sel, false);
- // If we found a getter then this may be a valid dot-reference, we
- // will look for the matching setter, in case it is needed.
- Selector SetterSel =
- SelectorTable::constructSetterName(PP.getIdentifierTable(),
- PP.getSelectorTable(), Member);
- ObjCMethodDecl *Setter = IFace->lookupClassMethod(SetterSel);
- if (!Setter) {
- // If this reference is in an @implementation, also check for 'private'
- // methods.
- Setter = IFace->lookupPrivateMethod(SetterSel, false);
- }
- // Look through local category implementations associated with the class.
- if (!Setter)
- Setter = IFace->getCategoryClassMethod(SetterSel);
-
- if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc))
- return ExprError();
-
- if (Getter || Setter) {
- QualType PType;
-
- ExprValueKind VK = VK_LValue;
- if (Getter) {
- PType = getMessageSendResultType(QualType(OT, 0), Getter, true,
- false);
- if (!getLangOptions().CPlusPlus &&
- IsCForbiddenLValueType(Context, PType))
- VK = VK_RValue;
- } else {
- // Get the expression type from Setter's incoming parameter.
- PType = (*(Setter->param_end() -1))->getType();
- }
- ExprObjectKind OK = (VK == VK_RValue ? OK_Ordinary : OK_ObjCProperty);
-
- // FIXME: we must check that the setter has property type.
- return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter,
- PType, VK, OK,
- MemberLoc, BaseExpr.take()));
- }
-
- if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr))
- return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
- ObjCImpDecl, HasTemplateArgs);
-
- return ExprError(Diag(MemberLoc, diag::err_property_not_found)
- << MemberName << BaseType);
- }
-
- // Normal property access.
- return HandleExprPropertyRefExpr(OPT, BaseExpr.get(), MemberName, MemberLoc,
- SourceLocation(), QualType(), false);
- }
-
- // Handle 'field access' to vectors, such as 'V.xx'.
- if (BaseType->isExtVectorType()) {
- // FIXME: this expr should store IsArrow.
- IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
- ExprValueKind VK = (IsArrow ? VK_LValue : BaseExpr.get()->getValueKind());
- QualType ret = CheckExtVectorComponent(*this, BaseType, VK, OpLoc,
- Member, MemberLoc);
- if (ret.isNull())
- return ExprError();
-
- return Owned(new (Context) ExtVectorElementExpr(ret, VK, BaseExpr.take(),
- *Member, MemberLoc));
- }
-
- // Adjust builtin-sel to the appropriate redefinition type if that's
- // not just a pointer to builtin-sel again.
- if (IsArrow &&
- BaseType->isSpecificBuiltinType(BuiltinType::ObjCSel) &&
- !Context.ObjCSelRedefinitionType->isObjCSelType()) {
- BaseExpr = ImpCastExprToType(BaseExpr.take(), Context.ObjCSelRedefinitionType,
- CK_BitCast);
- return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
- ObjCImpDecl, HasTemplateArgs);
- }
-
- // Failure cases.
- fail:
-
- // Recover from dot accesses to pointers, e.g.:
- // type *foo;
- // foo.bar
- // This is actually well-formed in two cases:
- // - 'type' is an Objective C type
- // - 'bar' is a pseudo-destructor name which happens to refer to
- // the appropriate pointer type
- if (const PointerType *Ptr = BaseType->getAs<PointerType>()) {
- if (!IsArrow && Ptr->getPointeeType()->isRecordType() &&
- MemberName.getNameKind() != DeclarationName::CXXDestructorName) {
- Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
- << BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange()
- << FixItHint::CreateReplacement(OpLoc, "->");
-
- // Recurse as an -> access.
- IsArrow = true;
- return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
- ObjCImpDecl, HasTemplateArgs);
- }
- }
-
- // If the user is trying to apply -> or . to a function name, it's probably
- // because they forgot parentheses to call that function.
- QualType ZeroArgCallTy;
- UnresolvedSet<4> Overloads;
- if (isExprCallable(*BaseExpr.get(), ZeroArgCallTy, Overloads)) {
- if (ZeroArgCallTy.isNull()) {
- Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call)
- << (Overloads.size() > 1) << 0 << BaseExpr.get()->getSourceRange();
- UnresolvedSet<2> PlausibleOverloads;
- for (OverloadExpr::decls_iterator It = Overloads.begin(),
- DeclsEnd = Overloads.end(); It != DeclsEnd; ++It) {
- const FunctionDecl *OverloadDecl = cast<FunctionDecl>(*It);
- QualType OverloadResultTy = OverloadDecl->getResultType();
- if ((!IsArrow && OverloadResultTy->isRecordType()) ||
- (IsArrow && OverloadResultTy->isPointerType() &&
- OverloadResultTy->getPointeeType()->isRecordType()))
- PlausibleOverloads.addDecl(It.getDecl());
- }
- NoteOverloads(PlausibleOverloads, BaseExpr.get()->getExprLoc());
- return ExprError();
- }
- if ((!IsArrow && ZeroArgCallTy->isRecordType()) ||
- (IsArrow && ZeroArgCallTy->isPointerType() &&
- ZeroArgCallTy->getPointeeType()->isRecordType())) {
- // At this point, we know BaseExpr looks like it's potentially callable
- // with 0 arguments, and that it returns something of a reasonable type,
- // so we can emit a fixit and carry on pretending that BaseExpr was
- // actually a CallExpr.
- SourceLocation ParenInsertionLoc =
- PP.getLocForEndOfToken(BaseExpr.get()->getLocEnd());
- Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call)
- << (Overloads.size() > 1) << 1 << BaseExpr.get()->getSourceRange()
- << FixItHint::CreateInsertion(ParenInsertionLoc, "()");
- // FIXME: Try this before emitting the fixit, and suppress diagnostics
- // while doing so.
- ExprResult NewBase =
- ActOnCallExpr(0, BaseExpr.take(), ParenInsertionLoc,
- MultiExprArg(*this, 0, 0),
- ParenInsertionLoc.getFileLocWithOffset(1));
- if (NewBase.isInvalid())
- return ExprError();
- BaseExpr = NewBase;
- BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take());
- return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
- ObjCImpDecl, HasTemplateArgs);
- }
- }
-
- Diag(MemberLoc, diag::err_typecheck_member_reference_struct_union)
- << BaseType << BaseExpr.get()->getSourceRange();
-
- return ExprError();
-}
-
-/// The main callback when the parser finds something like
-/// expression . [nested-name-specifier] identifier
-/// expression -> [nested-name-specifier] identifier
-/// where 'identifier' encompasses a fairly broad spectrum of
-/// possibilities, including destructor and operator references.
-///
-/// \param OpKind either tok::arrow or tok::period
-/// \param HasTrailingLParen whether the next token is '(', which
-/// is used to diagnose mis-uses of special members that can
-/// only be called
-/// \param ObjCImpDecl the current ObjC @implementation decl;
-/// this is an ugly hack around the fact that ObjC @implementations
-/// aren't properly put in the context chain
-ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
- SourceLocation OpLoc,
- tok::TokenKind OpKind,
- CXXScopeSpec &SS,
- UnqualifiedId &Id,
- Decl *ObjCImpDecl,
- bool HasTrailingLParen) {
- if (SS.isSet() && SS.isInvalid())
- return ExprError();
-
- // Warn about the explicit constructor calls Microsoft extension.
- if (getLangOptions().Microsoft &&
- Id.getKind() == UnqualifiedId::IK_ConstructorName)
- Diag(Id.getSourceRange().getBegin(),
- diag::ext_ms_explicit_constructor_call);
-
- TemplateArgumentListInfo TemplateArgsBuffer;
-
- // Decompose the name into its component parts.
- DeclarationNameInfo NameInfo;
- const TemplateArgumentListInfo *TemplateArgs;
- DecomposeUnqualifiedId(*this, Id, TemplateArgsBuffer,
- NameInfo, TemplateArgs);
-
- DeclarationName Name = NameInfo.getName();
- bool IsArrow = (OpKind == tok::arrow);
-
- NamedDecl *FirstQualifierInScope
- = (!SS.isSet() ? 0 : FindFirstQualifierInScope(S,
- static_cast<NestedNameSpecifier*>(SS.getScopeRep())));
-
- // This is a postfix expression, so get rid of ParenListExprs.
- ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Base);
- if (Result.isInvalid()) return ExprError();
- Base = Result.take();
-
- if (Base->getType()->isDependentType() || Name.isDependentName() ||
- isDependentScopeSpecifier(SS)) {
- Result = ActOnDependentMemberExpr(Base, Base->getType(),
- IsArrow, OpLoc,
- SS, FirstQualifierInScope,
- NameInfo, TemplateArgs);
- } else {
- LookupResult R(*this, NameInfo, LookupMemberName);
- ExprResult BaseResult = Owned(Base);
- Result = LookupMemberExpr(R, BaseResult, IsArrow, OpLoc,
- SS, ObjCImpDecl, TemplateArgs != 0);
- if (BaseResult.isInvalid())
- return ExprError();
- Base = BaseResult.take();
-
- if (Result.isInvalid()) {
- Owned(Base);
- return ExprError();
- }
-
- if (Result.get()) {
- // The only way a reference to a destructor can be used is to
- // immediately call it, which falls into this case. If the
- // next token is not a '(', produce a diagnostic and build the
- // call now.
- if (!HasTrailingLParen &&
- Id.getKind() == UnqualifiedId::IK_DestructorName)
- return DiagnoseDtorReference(NameInfo.getLoc(), Result.get());
-
- return move(Result);
- }
-
- Result = BuildMemberReferenceExpr(Base, Base->getType(),
- OpLoc, IsArrow, SS, FirstQualifierInScope,
- R, TemplateArgs);
- }
-
- return move(Result);
-}
-
ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
FunctionDecl *FD,
ParmVarDecl *Param) {
@@ -4716,6 +3169,7 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
MarkDeclarationReferenced(Param->getDefaultArg()->getLocStart(),
const_cast<CXXDestructorDecl*>(Temporary->getDestructor()));
ExprTemporaries.push_back(Temporary);
+ ExprNeedsCleanups = true;
}
// We already type-checked the argument, so we know it works.
@@ -4834,7 +3288,8 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
InitializedEntity Entity =
Param? InitializedEntity::InitializeParameter(Context, Param)
- : InitializedEntity::InitializeParameter(Context, ProtoArgType);
+ : InitializedEntity::InitializeParameter(Context, ProtoArgType,
+ Proto->isArgConsumed(i));
ExprResult ArgE = PerformCopyInitialization(Entity,
SourceLocation(),
Owned(Arg));
@@ -5157,7 +3612,8 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
if (Proto && i < Proto->getNumArgs()) {
InitializedEntity Entity
= InitializedEntity::InitializeParameter(Context,
- Proto->getArgType(i));
+ Proto->getArgType(i),
+ Proto->isArgConsumed(i));
ExprResult ArgE = PerformCopyInitialization(Entity,
SourceLocation(),
Owned(Arg));
@@ -5248,8 +3704,8 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
InitializedEntity Entity
= InitializedEntity::InitializeTemporary(literalType);
InitializationKind Kind
- = InitializationKind::CreateCast(SourceRange(LParenLoc, RParenLoc),
- /*IsCStyleCast=*/true);
+ = InitializationKind::CreateCStyleCast(LParenLoc,
+ SourceRange(LParenLoc, RParenLoc));
InitializationSequence InitSeq(*this, Entity, Kind, &literalExpr, 1);
ExprResult Result = InitSeq.Perform(*this, Entity, Kind,
MultiExprArg(*this, &literalExpr, 1),
@@ -5267,8 +3723,9 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
// In C, compound literals are l-values for some reason.
ExprValueKind VK = getLangOptions().CPlusPlus ? VK_RValue : VK_LValue;
- return Owned(new (Context) CompoundLiteralExpr(LParenLoc, TInfo, literalType,
- VK, literalExpr, isFileScope));
+ return MaybeBindToTemporary(
+ new (Context) CompoundLiteralExpr(LParenLoc, TInfo, literalType,
+ VK, literalExpr, isFileScope));
}
ExprResult
@@ -5426,14 +3883,15 @@ static CastKind PrepareScalarCast(Sema &S, ExprResult &Src, QualType DestTy) {
}
/// CheckCastTypes - Check type constraints for casting between types.
-ExprResult Sema::CheckCastTypes(SourceRange TyR, QualType castType,
- Expr *castExpr, CastKind& Kind, ExprValueKind &VK,
+ExprResult Sema::CheckCastTypes(SourceLocation CastStartLoc, SourceRange TyR,
+ QualType castType, Expr *castExpr,
+ CastKind& Kind, ExprValueKind &VK,
CXXCastPath &BasePath, bool FunctionalStyle) {
if (castExpr->getType() == Context.UnknownAnyTy)
return checkUnknownAnyCast(TyR, castType, castExpr, Kind, VK, BasePath);
if (getLangOptions().CPlusPlus)
- return CXXCheckCStyleCast(SourceRange(TyR.getBegin(),
+ return CXXCheckCStyleCast(SourceRange(CastStartLoc,
castExpr->getLocEnd()),
castType, VK, castExpr, Kind, BasePath,
FunctionalStyle);
@@ -5551,8 +4009,8 @@ ExprResult Sema::CheckCastTypes(SourceRange TyR, QualType castType,
// If either type is a pointer, the other type has to be either an
// integer or a pointer.
+ QualType castExprType = castExpr->getType();
if (!castType->isArithmeticType()) {
- QualType castExprType = castExpr->getType();
if (!castExprType->isIntegralType(Context) &&
castExprType->isArithmeticType()) {
Diag(castExpr->getLocStart(),
@@ -5568,6 +4026,36 @@ ExprResult Sema::CheckCastTypes(SourceRange TyR, QualType castType,
}
}
+ if (getLangOptions().ObjCAutoRefCount) {
+ // Diagnose problems with Objective-C casts involving lifetime qualifiers.
+ CheckObjCARCConversion(SourceRange(CastStartLoc, castExpr->getLocEnd()),
+ castType, castExpr, CCK_CStyleCast);
+
+ if (const PointerType *CastPtr = castType->getAs<PointerType>()) {
+ if (const PointerType *ExprPtr = castExprType->getAs<PointerType>()) {
+ Qualifiers CastQuals = CastPtr->getPointeeType().getQualifiers();
+ Qualifiers ExprQuals = ExprPtr->getPointeeType().getQualifiers();
+ if (CastPtr->getPointeeType()->isObjCLifetimeType() &&
+ ExprPtr->getPointeeType()->isObjCLifetimeType() &&
+ !CastQuals.compatiblyIncludesObjCLifetime(ExprQuals)) {
+ Diag(castExpr->getLocStart(),
+ diag::err_typecheck_incompatible_ownership)
+ << castExprType << castType << AA_Casting
+ << castExpr->getSourceRange();
+
+ return ExprError();
+ }
+ }
+ }
+ else if (!CheckObjCARCUnavailableWeakConversion(castType, castExprType)) {
+ Diag(castExpr->getLocStart(),
+ diag::err_arc_convesion_of_weak_unavailable) << 1
+ << castExprType << castType
+ << castExpr->getSourceRange();
+ return ExprError();
+ }
+ }
+
castExprRes = Owned(castExpr);
Kind = PrepareScalarCast(*this, castExprRes, castType);
if (castExprRes.isInvalid())
@@ -5638,20 +4126,57 @@ ExprResult Sema::CheckExtVectorCast(SourceRange R, QualType DestTy,
}
ExprResult
-Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, ParsedType Ty,
+Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc,
+ Declarator &D, ParsedType &Ty,
SourceLocation RParenLoc, Expr *castExpr) {
- assert((Ty != 0) && (castExpr != 0) &&
+ assert(!D.isInvalidType() && (castExpr != 0) &&
"ActOnCastExpr(): missing type or expr");
- TypeSourceInfo *castTInfo;
- QualType castType = GetTypeFromParser(Ty, &castTInfo);
- if (!castTInfo)
- castTInfo = Context.getTrivialTypeSourceInfo(castType);
+ TypeSourceInfo *castTInfo = GetTypeForDeclaratorCast(D, castExpr->getType());
+ if (D.isInvalidType())
+ return ExprError();
+
+ if (getLangOptions().CPlusPlus) {
+ // Check that there are no default arguments (C++ only).
+ CheckExtraCXXDefaultArguments(D);
+ }
+
+ QualType castType = castTInfo->getType();
+ Ty = CreateParsedType(castType, castTInfo);
+
+ bool isVectorLiteral = false;
+
+ // Check for an altivec or OpenCL literal,
+ // i.e. all the elements are integer constants.
+ ParenExpr *PE = dyn_cast<ParenExpr>(castExpr);
+ ParenListExpr *PLE = dyn_cast<ParenListExpr>(castExpr);
+ if (getLangOptions().AltiVec && castType->isVectorType() && (PE || PLE)) {
+ if (PLE && PLE->getNumExprs() == 0) {
+ Diag(PLE->getExprLoc(), diag::err_altivec_empty_initializer);
+ return ExprError();
+ }
+ if (PE || PLE->getNumExprs() == 1) {
+ Expr *E = (PE ? PE->getSubExpr() : PLE->getExpr(0));
+ if (!E->getType()->isVectorType())
+ isVectorLiteral = true;
+ }
+ else
+ isVectorLiteral = true;
+ }
+
+ // If this is a vector initializer, '(' type ')' '(' init, ..., init ')'
+ // then handle it as such.
+ if (isVectorLiteral)
+ return BuildVectorLiteral(LParenLoc, RParenLoc, castExpr, castTInfo);
// If the Expr being casted is a ParenListExpr, handle it specially.
- if (isa<ParenListExpr>(castExpr))
- return ActOnCastOfParenListExpr(S, LParenLoc, RParenLoc, castExpr,
- castTInfo);
+ // This is not an AltiVec-style cast, so turn the ParenListExpr into a
+ // sequence of BinOp comma operators.
+ if (isa<ParenListExpr>(castExpr)) {
+ ExprResult Result = MaybeConvertParenListExprToParenExpr(S, castExpr);
+ if (Result.isInvalid()) return ExprError();
+ castExpr = Result.take();
+ }
return BuildCStyleCastExpr(LParenLoc, castTInfo, RParenLoc, castExpr);
}
@@ -5663,8 +4188,8 @@ Sema::BuildCStyleCastExpr(SourceLocation LParenLoc, TypeSourceInfo *Ty,
ExprValueKind VK = VK_RValue;
CXXCastPath BasePath;
ExprResult CastResult =
- CheckCastTypes(SourceRange(LParenLoc, RParenLoc), Ty->getType(), castExpr,
- Kind, VK, BasePath);
+ CheckCastTypes(LParenLoc, SourceRange(LParenLoc, RParenLoc), Ty->getType(),
+ castExpr, Kind, VK, BasePath);
if (CastResult.isInvalid())
return ExprError();
castExpr = CastResult.take();
@@ -5675,6 +4200,80 @@ Sema::BuildCStyleCastExpr(SourceLocation LParenLoc, TypeSourceInfo *Ty,
LParenLoc, RParenLoc));
}
+ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc,
+ SourceLocation RParenLoc, Expr *E,
+ TypeSourceInfo *TInfo) {
+ assert((isa<ParenListExpr>(E) || isa<ParenExpr>(E)) &&
+ "Expected paren or paren list expression");
+
+ Expr **exprs;
+ unsigned numExprs;
+ Expr *subExpr;
+ if (ParenListExpr *PE = dyn_cast<ParenListExpr>(E)) {
+ exprs = PE->getExprs();
+ numExprs = PE->getNumExprs();
+ } else {
+ subExpr = cast<ParenExpr>(E)->getSubExpr();
+ exprs = &subExpr;
+ numExprs = 1;
+ }
+
+ QualType Ty = TInfo->getType();
+ assert(Ty->isVectorType() && "Expected vector type");
+
+ llvm::SmallVector<Expr *, 8> initExprs;
+ const VectorType *VTy = Ty->getAs<VectorType>();
+ unsigned numElems = Ty->getAs<VectorType>()->getNumElements();
+
+ // '(...)' form of vector initialization in AltiVec: the number of
+ // initializers must be one or must match the size of the vector.
+ // If a single value is specified in the initializer then it will be
+ // replicated to all the components of the vector
+ if (VTy->getVectorKind() == VectorType::AltiVecVector) {
+ // The number of initializers must be one or must match the size of the
+ // vector. If a single value is specified in the initializer then it will
+ // be replicated to all the components of the vector
+ if (numExprs == 1) {
+ QualType ElemTy = Ty->getAs<VectorType>()->getElementType();
+ ExprResult Literal = Owned(exprs[0]);
+ Literal = ImpCastExprToType(Literal.take(), ElemTy,
+ PrepareScalarCast(*this, Literal, ElemTy));
+ return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, Literal.take());
+ }
+ else if (numExprs < numElems) {
+ Diag(E->getExprLoc(),
+ diag::err_incorrect_number_of_vector_initializers);
+ return ExprError();
+ }
+ else
+ for (unsigned i = 0, e = numExprs; i != e; ++i)
+ initExprs.push_back(exprs[i]);
+ }
+ else {
+ // For OpenCL, when the number of initializers is a single value,
+ // it will be replicated to all components of the vector.
+ if (getLangOptions().OpenCL &&
+ VTy->getVectorKind() == VectorType::GenericVector &&
+ numExprs == 1) {
+ QualType ElemTy = Ty->getAs<VectorType>()->getElementType();
+ ExprResult Literal = Owned(exprs[0]);
+ Literal = ImpCastExprToType(Literal.take(), ElemTy,
+ PrepareScalarCast(*this, Literal, ElemTy));
+ return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, Literal.take());
+ }
+
+ for (unsigned i = 0, e = numExprs; i != e; ++i)
+ initExprs.push_back(exprs[i]);
+ }
+ // FIXME: This means that pretty-printing the final AST will produce curly
+ // braces instead of the original commas.
+ InitListExpr *initE = new (Context) InitListExpr(Context, LParenLoc,
+ &initExprs[0],
+ initExprs.size(), RParenLoc);
+ initE->setType(Ty);
+ return BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, initE);
+}
+
/// This is not an AltiVec-style cast, so turn the ParenListExpr into a sequence
/// of comma binary operators.
ExprResult
@@ -5694,91 +4293,18 @@ Sema::MaybeConvertParenListExprToParenExpr(Scope *S, Expr *expr) {
return ActOnParenExpr(E->getLParenLoc(), E->getRParenLoc(), Result.get());
}
-ExprResult
-Sema::ActOnCastOfParenListExpr(Scope *S, SourceLocation LParenLoc,
- SourceLocation RParenLoc, Expr *Op,
- TypeSourceInfo *TInfo) {
- ParenListExpr *PE = cast<ParenListExpr>(Op);
- QualType Ty = TInfo->getType();
- bool isVectorLiteral = false;
-
- // Check for an altivec or OpenCL literal,
- // i.e. all the elements are integer constants.
- if (getLangOptions().AltiVec && Ty->isVectorType()) {
- if (PE->getNumExprs() == 0) {
- Diag(PE->getExprLoc(), diag::err_altivec_empty_initializer);
- return ExprError();
- }
- if (PE->getNumExprs() == 1) {
- if (!PE->getExpr(0)->getType()->isVectorType())
- isVectorLiteral = true;
- }
- else
- isVectorLiteral = true;
- }
-
- // If this is a vector initializer, '(' type ')' '(' init, ..., init ')'
- // then handle it as such.
- if (isVectorLiteral) {
- llvm::SmallVector<Expr *, 8> initExprs;
- // '(...)' form of vector initialization in AltiVec: the number of
- // initializers must be one or must match the size of the vector.
- // If a single value is specified in the initializer then it will be
- // replicated to all the components of the vector
- if (Ty->getAs<VectorType>()->getVectorKind() ==
- VectorType::AltiVecVector) {
- unsigned numElems = Ty->getAs<VectorType>()->getNumElements();
- // The number of initializers must be one or must match the size of the
- // vector. If a single value is specified in the initializer then it will
- // be replicated to all the components of the vector
- if (PE->getNumExprs() == 1) {
- QualType ElemTy = Ty->getAs<VectorType>()->getElementType();
- ExprResult Literal = Owned(PE->getExpr(0));
- Literal = ImpCastExprToType(Literal.take(), ElemTy,
- PrepareScalarCast(*this, Literal, ElemTy));
- return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, Literal.take());
- }
- else if (PE->getNumExprs() < numElems) {
- Diag(PE->getExprLoc(),
- diag::err_incorrect_number_of_vector_initializers);
- return ExprError();
- }
- else
- for (unsigned i = 0, e = PE->getNumExprs(); i != e; ++i)
- initExprs.push_back(PE->getExpr(i));
- }
- else
- for (unsigned i = 0, e = PE->getNumExprs(); i != e; ++i)
- initExprs.push_back(PE->getExpr(i));
-
- // FIXME: This means that pretty-printing the final AST will produce curly
- // braces instead of the original commas.
- InitListExpr *E = new (Context) InitListExpr(Context, LParenLoc,
- &initExprs[0],
- initExprs.size(), RParenLoc);
- E->setType(Ty);
- return BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, E);
- } else {
- // This is not an AltiVec-style cast, so turn the ParenListExpr into a
- // sequence of BinOp comma operators.
- ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Op);
- if (Result.isInvalid()) return ExprError();
- return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, Result.take());
- }
-}
-
ExprResult Sema::ActOnParenOrParenListExpr(SourceLocation L,
SourceLocation R,
- MultiExprArg Val,
- ParsedType TypeOfCast) {
+ MultiExprArg Val) {
unsigned nexprs = Val.size();
Expr **exprs = reinterpret_cast<Expr**>(Val.release());
assert((exprs != 0) && "ActOnParenOrParenListExpr() missing expr list");
Expr *expr;
- if (nexprs == 1 && TypeOfCast && !TypeIsVectorType(TypeOfCast))
+ if (nexprs == 1)
expr = new (Context) ParenExpr(L, R, exprs[0]);
else
- expr = new (Context) ParenListExpr(Context, L, exprs, nexprs, R);
+ expr = new (Context) ParenListExpr(Context, L, exprs, nexprs, R,
+ exprs[nexprs-1]->getType());
return Owned(expr);
}
@@ -5876,7 +4402,7 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, ExprR
// Now check the two expressions.
if (LHSTy->isVectorType() || RHSTy->isVectorType())
- return CheckVectorOperands(QuestionLoc, LHS, RHS);
+ return CheckVectorOperands(LHS, RHS, QuestionLoc, /*isCompAssign*/false);
// OpenCL: If the condition is a vector, and both operands are scalar,
// attempt to implicity convert them to the vector type to act like the
@@ -6203,43 +4729,21 @@ QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS,
return QualType();
}
-/// SuggestParentheses - Emit a diagnostic together with a fixit hint that wraps
+/// SuggestParentheses - Emit a note with a fixit hint that wraps
/// ParenRange in parentheses.
static void SuggestParentheses(Sema &Self, SourceLocation Loc,
- const PartialDiagnostic &PD,
- const PartialDiagnostic &FirstNote,
- SourceRange FirstParenRange,
- const PartialDiagnostic &SecondNote,
- SourceRange SecondParenRange) {
- Self.Diag(Loc, PD);
-
- if (!FirstNote.getDiagID())
- return;
-
- SourceLocation EndLoc = Self.PP.getLocForEndOfToken(FirstParenRange.getEnd());
- if (!FirstParenRange.getEnd().isFileID() || EndLoc.isInvalid()) {
- // We can't display the parentheses, so just return.
- return;
- }
-
- Self.Diag(Loc, FirstNote)
- << FixItHint::CreateInsertion(FirstParenRange.getBegin(), "(")
- << FixItHint::CreateInsertion(EndLoc, ")");
-
- if (!SecondNote.getDiagID())
- return;
-
- EndLoc = Self.PP.getLocForEndOfToken(SecondParenRange.getEnd());
- if (!SecondParenRange.getEnd().isFileID() || EndLoc.isInvalid()) {
- // We can't display the parentheses, so just dig the
- // warning/error and return.
- Self.Diag(Loc, SecondNote);
- return;
+ const PartialDiagnostic &Note,
+ SourceRange ParenRange) {
+ SourceLocation EndLoc = Self.PP.getLocForEndOfToken(ParenRange.getEnd());
+ if (ParenRange.getBegin().isFileID() && ParenRange.getEnd().isFileID() &&
+ EndLoc.isValid()) {
+ Self.Diag(Loc, Note)
+ << FixItHint::CreateInsertion(ParenRange.getBegin(), "(")
+ << FixItHint::CreateInsertion(EndLoc, ")");
+ } else {
+ // We can't display the parentheses, so just show the bare note.
+ Self.Diag(Loc, Note) << ParenRange;
}
-
- Self.Diag(Loc, SecondNote)
- << FixItHint::CreateInsertion(SecondParenRange.getBegin(), "(")
- << FixItHint::CreateInsertion(EndLoc, ")");
}
static bool IsArithmeticOp(BinaryOperatorKind Opc) {
@@ -6312,13 +4816,13 @@ static bool ExprLooksBoolean(Expr *E) {
/// "int x = a + someBinaryCondition ? 1 : 2".
static void DiagnoseConditionalPrecedence(Sema &Self,
SourceLocation OpLoc,
- Expr *cond,
- Expr *lhs,
- Expr *rhs) {
+ Expr *Condition,
+ Expr *LHS,
+ Expr *RHS) {
BinaryOperatorKind CondOpcode;
Expr *CondRHS;
- if (!IsArithmeticBinaryExpr(cond, &CondOpcode, &CondRHS))
+ if (!IsArithmeticBinaryExpr(Condition, &CondOpcode, &CondRHS))
return;
if (!ExprLooksBoolean(CondRHS))
return;
@@ -6326,25 +4830,18 @@ static void DiagnoseConditionalPrecedence(Sema &Self,
// The condition is an arithmetic binary expression, with a right-
// hand side that looks boolean, so warn.
- PartialDiagnostic Warn = Self.PDiag(diag::warn_precedence_conditional)
- << cond->getSourceRange()
- << BinaryOperator::getOpcodeStr(CondOpcode);
-
- PartialDiagnostic FirstNote =
- Self.PDiag(diag::note_precedence_conditional_silence)
+ Self.Diag(OpLoc, diag::warn_precedence_conditional)
+ << Condition->getSourceRange()
<< BinaryOperator::getOpcodeStr(CondOpcode);
- SourceRange FirstParenRange(cond->getLocStart(),
- cond->getLocEnd());
-
- PartialDiagnostic SecondNote =
- Self.PDiag(diag::note_precedence_conditional_first);
-
- SourceRange SecondParenRange(CondRHS->getLocStart(),
- rhs->getLocEnd());
+ SuggestParentheses(Self, OpLoc,
+ Self.PDiag(diag::note_precedence_conditional_silence)
+ << BinaryOperator::getOpcodeStr(CondOpcode),
+ SourceRange(Condition->getLocStart(), Condition->getLocEnd()));
- SuggestParentheses(Self, OpLoc, Warn, FirstNote, FirstParenRange,
- SecondNote, SecondParenRange);
+ SuggestParentheses(Self, OpLoc,
+ Self.PDiag(diag::note_precedence_conditional_first),
+ SourceRange(CondRHS->getLocStart(), RHS->getLocEnd()));
}
/// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null
@@ -6427,17 +4924,31 @@ checkPointerTypesForAssignment(Sema &S, QualType lhsType, QualType rhsType) {
// qualifiers of the type *pointed to* by the right;
Qualifiers lq;
+ // As a special case, 'non-__weak A *' -> 'non-__weak const *' is okay.
+ if (lhq.getObjCLifetime() != rhq.getObjCLifetime() &&
+ lhq.compatiblyIncludesObjCLifetime(rhq)) {
+ // Ignore lifetime for further calculation.
+ lhq.removeObjCLifetime();
+ rhq.removeObjCLifetime();
+ }
+
if (!lhq.compatiblyIncludes(rhq)) {
// Treat address-space mismatches as fatal. TODO: address subspaces
if (lhq.getAddressSpace() != rhq.getAddressSpace())
ConvTy = Sema::IncompatiblePointerDiscardsQualifiers;
- // It's okay to add or remove GC qualifiers when converting to
+ // It's okay to add or remove GC or lifetime qualifiers when converting to
// and from void*.
- else if (lhq.withoutObjCGCAttr().compatiblyIncludes(rhq.withoutObjCGCAttr())
+ else if (lhq.withoutObjCGCAttr().withoutObjCGLifetime()
+ .compatiblyIncludes(
+ rhq.withoutObjCGCAttr().withoutObjCGLifetime())
&& (lhptee->isVoidType() || rhptee->isVoidType()))
; // keep old
+ // Treat lifetime mismatches as fatal.
+ else if (lhq.getObjCLifetime() != rhq.getObjCLifetime())
+ ConvTy = Sema::IncompatiblePointerDiscardsQualifiers;
+
// For GCC compatibility, other qualifier mismatches are treated
// as still compatible in C.
else ConvTy = Sema::CompatiblePointerDiscardsQualifiers;
@@ -6614,6 +5125,7 @@ Sema::AssignConvertType
Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs,
CastKind &Kind) {
QualType rhsType = rhs.get()->getType();
+ QualType origLhsType = lhsType;
// Get canonical types. We're not formatting these types, just comparing
// them.
@@ -6768,7 +5280,13 @@ Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs,
// A* -> B*
if (rhsType->isObjCObjectPointerType()) {
Kind = CK_BitCast;
- return checkObjCPointerTypesForAssignment(*this, lhsType, rhsType);
+ Sema::AssignConvertType result =
+ checkObjCPointerTypesForAssignment(*this, lhsType, rhsType);
+ if (getLangOptions().ObjCAutoRefCount &&
+ result == Compatible &&
+ !CheckObjCARCUnavailableWeakConversion(origLhsType, rhsType))
+ result = IncompatibleObjCWeakRef;
+ return result;
}
// int or null -> A*
@@ -6936,8 +5454,12 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, ExprResult &rExpr) {
AA_Assigning);
if (Res.isInvalid())
return Incompatible;
+ Sema::AssignConvertType result = Compatible;
+ if (getLangOptions().ObjCAutoRefCount &&
+ !CheckObjCARCUnavailableWeakConversion(lhsType, rExpr.get()->getType()))
+ result = IncompatibleObjCWeakRef;
rExpr = move(Res);
- return Compatible;
+ return result;
}
// FIXME: Currently, we fall through and treat C++ classes like C
@@ -6989,7 +5511,8 @@ QualType Sema::InvalidOperands(SourceLocation Loc, ExprResult &lex, ExprResult &
return QualType();
}
-QualType Sema::CheckVectorOperands(SourceLocation Loc, ExprResult &lex, ExprResult &rex) {
+QualType Sema::CheckVectorOperands(ExprResult &lex, ExprResult &rex,
+ SourceLocation Loc, bool isCompAssign) {
// For conversion purposes, we ignore any qualifiers.
// For example, "const float" and "float" are equivalent.
QualType lhsType =
@@ -7001,42 +5524,33 @@ QualType Sema::CheckVectorOperands(SourceLocation Loc, ExprResult &lex, ExprResu
if (lhsType == rhsType)
return lhsType;
- // Handle the case of a vector & extvector type of the same size and element
- // type. It would be nice if we only had one vector type someday.
- if (getLangOptions().LaxVectorConversions) {
- if (const VectorType *LV = lhsType->getAs<VectorType>()) {
- if (const VectorType *RV = rhsType->getAs<VectorType>()) {
- if (LV->getElementType() == RV->getElementType() &&
- LV->getNumElements() == RV->getNumElements()) {
- if (lhsType->isExtVectorType()) {
- rex = ImpCastExprToType(rex.take(), lhsType, CK_BitCast);
- return lhsType;
- }
-
- lex = ImpCastExprToType(lex.take(), rhsType, CK_BitCast);
- return rhsType;
- } else if (Context.getTypeSize(lhsType) ==Context.getTypeSize(rhsType)){
- // If we are allowing lax vector conversions, and LHS and RHS are both
- // vectors, the total size only needs to be the same. This is a
- // bitcast; no bits are changed but the result type is different.
- rex = ImpCastExprToType(rex.take(), lhsType, CK_BitCast);
- return lhsType;
- }
- }
- }
- }
-
// Handle the case of equivalent AltiVec and GCC vector types
if (lhsType->isVectorType() && rhsType->isVectorType() &&
Context.areCompatibleVectorTypes(lhsType, rhsType)) {
- lex = ImpCastExprToType(lex.take(), rhsType, CK_BitCast);
+ if (lhsType->isExtVectorType()) {
+ rex = ImpCastExprToType(rex.take(), lhsType, CK_BitCast);
+ return lhsType;
+ }
+
+ if (!isCompAssign)
+ lex = ImpCastExprToType(lex.take(), rhsType, CK_BitCast);
return rhsType;
}
+ if (getLangOptions().LaxVectorConversions &&
+ Context.getTypeSize(lhsType) == Context.getTypeSize(rhsType)) {
+ // If we are allowing lax vector conversions, and LHS and RHS are both
+ // vectors, the total size only needs to be the same. This is a
+ // bitcast; no bits are changed but the result type is different.
+ // FIXME: Should we really be allowing this?
+ rex = ImpCastExprToType(rex.take(), lhsType, CK_BitCast);
+ return lhsType;
+ }
+
// Canonicalize the ExtVector to the LHS, remember if we swapped so we can
// swap back (so that we don't reverse the inputs to a subtract, for instance.
bool swapped = false;
- if (rhsType->isExtVectorType()) {
+ if (rhsType->isExtVectorType() && !isCompAssign) {
swapped = true;
std::swap(rex, lex);
std::swap(rhsType, lhsType);
@@ -7069,6 +5583,7 @@ QualType Sema::CheckVectorOperands(SourceLocation Loc, ExprResult &lex, ExprResu
}
// Vectors of different size or scalar and non-ext-vector are errors.
+ if (swapped) std::swap(rex, lex);
Diag(Loc, diag::err_typecheck_vector_not_convertable)
<< lex.get()->getType() << rex.get()->getType()
<< lex.get()->getSourceRange() << rex.get()->getSourceRange();
@@ -7078,7 +5593,7 @@ QualType Sema::CheckVectorOperands(SourceLocation Loc, ExprResult &lex, ExprResu
QualType Sema::CheckMultiplyDivideOperands(
ExprResult &lex, ExprResult &rex, SourceLocation Loc, bool isCompAssign, bool isDiv) {
if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType())
- return CheckVectorOperands(Loc, lex, rex);
+ return CheckVectorOperands(lex, rex, Loc, isCompAssign);
QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign);
if (lex.isInvalid() || rex.isInvalid())
@@ -7102,7 +5617,7 @@ QualType Sema::CheckRemainderOperands(
if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) {
if (lex.get()->getType()->hasIntegerRepresentation() &&
rex.get()->getType()->hasIntegerRepresentation())
- return CheckVectorOperands(Loc, lex, rex);
+ return CheckVectorOperands(lex, rex, Loc, isCompAssign);
return InvalidOperands(Loc, lex, rex);
}
@@ -7121,10 +5636,149 @@ QualType Sema::CheckRemainderOperands(
return compType;
}
+/// \brief Diagnose invalid arithmetic on two void pointers.
+static void diagnoseArithmeticOnTwoVoidPointers(Sema &S, SourceLocation Loc,
+ Expr *LHS, Expr *RHS) {
+ S.Diag(Loc, S.getLangOptions().CPlusPlus
+ ? diag::err_typecheck_pointer_arith_void_type
+ : diag::ext_gnu_void_ptr)
+ << 1 /* two pointers */ << LHS->getSourceRange() << RHS->getSourceRange();
+}
+
+/// \brief Diagnose invalid arithmetic on a void pointer.
+static void diagnoseArithmeticOnVoidPointer(Sema &S, SourceLocation Loc,
+ Expr *Pointer) {
+ S.Diag(Loc, S.getLangOptions().CPlusPlus
+ ? diag::err_typecheck_pointer_arith_void_type
+ : diag::ext_gnu_void_ptr)
+ << 0 /* one pointer */ << Pointer->getSourceRange();
+}
+
+/// \brief Diagnose invalid arithmetic on two function pointers.
+static void diagnoseArithmeticOnTwoFunctionPointers(Sema &S, SourceLocation Loc,
+ Expr *LHS, Expr *RHS) {
+ assert(LHS->getType()->isAnyPointerType());
+ assert(RHS->getType()->isAnyPointerType());
+ S.Diag(Loc, S.getLangOptions().CPlusPlus
+ ? diag::err_typecheck_pointer_arith_function_type
+ : diag::ext_gnu_ptr_func_arith)
+ << 1 /* two pointers */ << LHS->getType()->getPointeeType()
+ // We only show the second type if it differs from the first.
+ << (unsigned)!S.Context.hasSameUnqualifiedType(LHS->getType(),
+ RHS->getType())
+ << RHS->getType()->getPointeeType()
+ << LHS->getSourceRange() << RHS->getSourceRange();
+}
+
+/// \brief Diagnose invalid arithmetic on a function pointer.
+static void diagnoseArithmeticOnFunctionPointer(Sema &S, SourceLocation Loc,
+ Expr *Pointer) {
+ assert(Pointer->getType()->isAnyPointerType());
+ S.Diag(Loc, S.getLangOptions().CPlusPlus
+ ? diag::err_typecheck_pointer_arith_function_type
+ : diag::ext_gnu_ptr_func_arith)
+ << 0 /* one pointer */ << Pointer->getType()->getPointeeType()
+ << 0 /* one pointer, so only one type */
+ << Pointer->getSourceRange();
+}
+
+/// \brief Check the validity of an arithmetic pointer operand.
+///
+/// If the operand has pointer type, this code will check for pointer types
+/// which are invalid in arithmetic operations. These will be diagnosed
+/// appropriately, including whether or not the use is supported as an
+/// extension.
+///
+/// \returns True when the operand is valid to use (even if as an extension).
+static bool checkArithmeticOpPointerOperand(Sema &S, SourceLocation Loc,
+ Expr *Operand) {
+ if (!Operand->getType()->isAnyPointerType()) return true;
+
+ QualType PointeeTy = Operand->getType()->getPointeeType();
+ if (PointeeTy->isVoidType()) {
+ diagnoseArithmeticOnVoidPointer(S, Loc, Operand);
+ return !S.getLangOptions().CPlusPlus;
+ }
+ if (PointeeTy->isFunctionType()) {
+ diagnoseArithmeticOnFunctionPointer(S, Loc, Operand);
+ return !S.getLangOptions().CPlusPlus;
+ }
+
+ if ((Operand->getType()->isPointerType() &&
+ !Operand->getType()->isDependentType()) ||
+ Operand->getType()->isObjCObjectPointerType()) {
+ QualType PointeeTy = Operand->getType()->getPointeeType();
+ if (S.RequireCompleteType(
+ Loc, PointeeTy,
+ S.PDiag(diag::err_typecheck_arithmetic_incomplete_type)
+ << PointeeTy << Operand->getSourceRange()))
+ return false;
+ }
+
+ return true;
+}
+
+/// \brief Check the validity of a binary arithmetic operation w.r.t. pointer
+/// operands.
+///
+/// This routine will diagnose any invalid arithmetic on pointer operands much
+/// like \see checkArithmeticOpPointerOperand. However, it has special logic
+/// for emitting a single diagnostic even for operations where both LHS and RHS
+/// are (potentially problematic) pointers.
+///
+/// \returns True when the operand is valid to use (even if as an extension).
+static bool checkArithmeticBinOpPointerOperands(Sema &S, SourceLocation Loc,
+ Expr *LHS, Expr *RHS) {
+ bool isLHSPointer = LHS->getType()->isAnyPointerType();
+ bool isRHSPointer = RHS->getType()->isAnyPointerType();
+ if (!isLHSPointer && !isRHSPointer) return true;
+
+ QualType LHSPointeeTy, RHSPointeeTy;
+ if (isLHSPointer) LHSPointeeTy = LHS->getType()->getPointeeType();
+ if (isRHSPointer) RHSPointeeTy = RHS->getType()->getPointeeType();
+
+ // Check for arithmetic on pointers to incomplete types.
+ bool isLHSVoidPtr = isLHSPointer && LHSPointeeTy->isVoidType();
+ bool isRHSVoidPtr = isRHSPointer && RHSPointeeTy->isVoidType();
+ if (isLHSVoidPtr || isRHSVoidPtr) {
+ if (!isRHSVoidPtr) diagnoseArithmeticOnVoidPointer(S, Loc, LHS);
+ else if (!isLHSVoidPtr) diagnoseArithmeticOnVoidPointer(S, Loc, RHS);
+ else diagnoseArithmeticOnTwoVoidPointers(S, Loc, LHS, RHS);
+
+ return !S.getLangOptions().CPlusPlus;
+ }
+
+ bool isLHSFuncPtr = isLHSPointer && LHSPointeeTy->isFunctionType();
+ bool isRHSFuncPtr = isRHSPointer && RHSPointeeTy->isFunctionType();
+ if (isLHSFuncPtr || isRHSFuncPtr) {
+ if (!isRHSFuncPtr) diagnoseArithmeticOnFunctionPointer(S, Loc, LHS);
+ else if (!isLHSFuncPtr) diagnoseArithmeticOnFunctionPointer(S, Loc, RHS);
+ else diagnoseArithmeticOnTwoFunctionPointers(S, Loc, LHS, RHS);
+
+ return !S.getLangOptions().CPlusPlus;
+ }
+
+ Expr *Operands[] = { LHS, RHS };
+ for (unsigned i = 0; i < 2; ++i) {
+ Expr *Operand = Operands[i];
+ if ((Operand->getType()->isPointerType() &&
+ !Operand->getType()->isDependentType()) ||
+ Operand->getType()->isObjCObjectPointerType()) {
+ QualType PointeeTy = Operand->getType()->getPointeeType();
+ if (S.RequireCompleteType(
+ Loc, PointeeTy,
+ S.PDiag(diag::err_typecheck_arithmetic_incomplete_type)
+ << PointeeTy << Operand->getSourceRange()))
+ return false;
+ }
+ }
+ return true;
+}
+
QualType Sema::CheckAdditionOperands( // C99 6.5.6
ExprResult &lex, ExprResult &rex, SourceLocation Loc, QualType* CompLHSTy) {
if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) {
- QualType compType = CheckVectorOperands(Loc, lex, rex);
+ QualType compType = CheckVectorOperands(lex, rex, Loc, CompLHSTy);
if (CompLHSTy) *CompLHSTy = compType;
return compType;
}
@@ -7146,42 +5800,12 @@ QualType Sema::CheckAdditionOperands( // C99 6.5.6
std::swap(PExp, IExp);
if (PExp->getType()->isAnyPointerType()) {
-
if (IExp->getType()->isIntegerType()) {
- QualType PointeeTy = PExp->getType()->getPointeeType();
-
- // Check for arithmetic on pointers to incomplete types.
- if (PointeeTy->isVoidType()) {
- if (getLangOptions().CPlusPlus) {
- Diag(Loc, diag::err_typecheck_pointer_arith_void_type)
- << lex.get()->getSourceRange() << rex.get()->getSourceRange();
- return QualType();
- }
+ if (!checkArithmeticOpPointerOperand(*this, Loc, PExp))
+ return QualType();
- // GNU extension: arithmetic on pointer to void
- Diag(Loc, diag::ext_gnu_void_ptr)
- << lex.get()->getSourceRange() << rex.get()->getSourceRange();
- } else if (PointeeTy->isFunctionType()) {
- if (getLangOptions().CPlusPlus) {
- Diag(Loc, diag::err_typecheck_pointer_arith_function_type)
- << lex.get()->getType() << lex.get()->getSourceRange();
- return QualType();
- }
+ QualType PointeeTy = PExp->getType()->getPointeeType();
- // GNU extension: arithmetic on pointer to function
- Diag(Loc, diag::ext_gnu_ptr_func_arith)
- << lex.get()->getType() << lex.get()->getSourceRange();
- } else {
- // Check if we require a complete type.
- if (((PExp->getType()->isPointerType() &&
- !PExp->getType()->isDependentType()) ||
- PExp->getType()->isObjCObjectPointerType()) &&
- RequireCompleteType(Loc, PointeeTy,
- PDiag(diag::err_typecheck_arithmetic_incomplete_type)
- << PExp->getSourceRange()
- << PExp->getType()))
- return QualType();
- }
// Diagnose bad cases where we step over interface counts.
if (PointeeTy->isObjCObjectType() && LangOpts.ObjCNonFragileABI) {
Diag(Loc, diag::err_arithmetic_nonfragile_interface)
@@ -7209,7 +5833,7 @@ QualType Sema::CheckAdditionOperands( // C99 6.5.6
QualType Sema::CheckSubtractionOperands(ExprResult &lex, ExprResult &rex,
SourceLocation Loc, QualType* CompLHSTy) {
if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) {
- QualType compType = CheckVectorOperands(Loc, lex, rex);
+ QualType compType = CheckVectorOperands(lex, rex, Loc, CompLHSTy);
if (CompLHSTy) *CompLHSTy = compType;
return compType;
}
@@ -7231,35 +5855,6 @@ QualType Sema::CheckSubtractionOperands(ExprResult &lex, ExprResult &rex,
if (lex.get()->getType()->isAnyPointerType()) {
QualType lpointee = lex.get()->getType()->getPointeeType();
- // The LHS must be an completely-defined object type.
-
- bool ComplainAboutVoid = false;
- Expr *ComplainAboutFunc = 0;
- if (lpointee->isVoidType()) {
- if (getLangOptions().CPlusPlus) {
- Diag(Loc, diag::err_typecheck_pointer_arith_void_type)
- << lex.get()->getSourceRange() << rex.get()->getSourceRange();
- return QualType();
- }
-
- // GNU C extension: arithmetic on pointer to void
- ComplainAboutVoid = true;
- } else if (lpointee->isFunctionType()) {
- if (getLangOptions().CPlusPlus) {
- Diag(Loc, diag::err_typecheck_pointer_arith_function_type)
- << lex.get()->getType() << lex.get()->getSourceRange();
- return QualType();
- }
-
- // GNU C extension: arithmetic on pointer to function
- ComplainAboutFunc = lex.get();
- } else if (!lpointee->isDependentType() &&
- RequireCompleteType(Loc, lpointee,
- PDiag(diag::err_typecheck_sub_ptr_object)
- << lex.get()->getSourceRange()
- << lex.get()->getType()))
- return QualType();
-
// Diagnose bad cases where we step over interface counts.
if (lpointee->isObjCObjectType() && LangOpts.ObjCNonFragileABI) {
Diag(Loc, diag::err_arithmetic_nonfragile_interface)
@@ -7269,13 +5864,8 @@ QualType Sema::CheckSubtractionOperands(ExprResult &lex, ExprResult &rex,
// The result type of a pointer-int computation is the pointer type.
if (rex.get()->getType()->isIntegerType()) {
- if (ComplainAboutVoid)
- Diag(Loc, diag::ext_gnu_void_ptr)
- << lex.get()->getSourceRange() << rex.get()->getSourceRange();
- if (ComplainAboutFunc)
- Diag(Loc, diag::ext_gnu_ptr_func_arith)
- << ComplainAboutFunc->getType()
- << ComplainAboutFunc->getSourceRange();
+ if (!checkArithmeticOpPointerOperand(*this, Loc, lex.get()))
+ return QualType();
if (CompLHSTy) *CompLHSTy = lex.get()->getType();
return lex.get()->getType();
@@ -7285,33 +5875,6 @@ QualType Sema::CheckSubtractionOperands(ExprResult &lex, ExprResult &rex,
if (const PointerType *RHSPTy = rex.get()->getType()->getAs<PointerType>()) {
QualType rpointee = RHSPTy->getPointeeType();
- // RHS must be a completely-type object type.
- // Handle the GNU void* extension.
- if (rpointee->isVoidType()) {
- if (getLangOptions().CPlusPlus) {
- Diag(Loc, diag::err_typecheck_pointer_arith_void_type)
- << lex.get()->getSourceRange() << rex.get()->getSourceRange();
- return QualType();
- }
-
- ComplainAboutVoid = true;
- } else if (rpointee->isFunctionType()) {
- if (getLangOptions().CPlusPlus) {
- Diag(Loc, diag::err_typecheck_pointer_arith_function_type)
- << rex.get()->getType() << rex.get()->getSourceRange();
- return QualType();
- }
-
- // GNU extension: arithmetic on pointer to function
- if (!ComplainAboutFunc)
- ComplainAboutFunc = rex.get();
- } else if (!rpointee->isDependentType() &&
- RequireCompleteType(Loc, rpointee,
- PDiag(diag::err_typecheck_sub_ptr_object)
- << rex.get()->getSourceRange()
- << rex.get()->getType()))
- return QualType();
-
if (getLangOptions().CPlusPlus) {
// Pointee types must be the same: C++ [expr.add]
if (!Context.hasSameUnqualifiedType(lpointee, rpointee)) {
@@ -7332,13 +5895,9 @@ QualType Sema::CheckSubtractionOperands(ExprResult &lex, ExprResult &rex,
}
}
- if (ComplainAboutVoid)
- Diag(Loc, diag::ext_gnu_void_ptr)
- << lex.get()->getSourceRange() << rex.get()->getSourceRange();
- if (ComplainAboutFunc)
- Diag(Loc, diag::ext_gnu_ptr_func_arith)
- << ComplainAboutFunc->getType()
- << ComplainAboutFunc->getSourceRange();
+ if (!checkArithmeticBinOpPointerOperands(*this, Loc,
+ lex.get(), rex.get()))
+ return QualType();
if (CompLHSTy) *CompLHSTy = lex.get()->getType();
return Context.getPointerDiffType();
@@ -7394,19 +5953,24 @@ static void DiagnoseBadShiftValues(Sema& S, ExprResult &lex, ExprResult &rex,
llvm::APSInt Result = Left.extend(ResultBits.getLimitedValue());
Result = Result.shl(Right);
+ // Print the bit representation of the signed integer as an unsigned
+ // hexadecimal number.
+ llvm::SmallString<40> HexResult;
+ Result.toString(HexResult, 16, /*Signed =*/false, /*Literal =*/true);
+
// If we are only missing a sign bit, this is less likely to result in actual
// bugs -- if the result is cast back to an unsigned type, it will have the
// expected value. Thus we place this behind a different warning that can be
// turned off separately if needed.
if (LeftBits == ResultBits - 1) {
- S.Diag(Loc, diag::warn_shift_result_overrides_sign_bit)
- << Result.toString(10) << LHSTy
+ S.Diag(Loc, diag::warn_shift_result_sets_sign_bit)
+ << HexResult.str() << LHSTy
<< lex.get()->getSourceRange() << rex.get()->getSourceRange();
return;
}
S.Diag(Loc, diag::warn_shift_result_gt_typewidth)
- << Result.toString(10) << Result.getMinSignedBits() << LHSTy
+ << HexResult.str() << Result.getMinSignedBits() << LHSTy
<< Left.getBitWidth() << lex.get()->getSourceRange() << rex.get()->getSourceRange();
}
@@ -7427,7 +5991,7 @@ QualType Sema::CheckShiftOperands(ExprResult &lex, ExprResult &rex, SourceLocati
// Vector shifts promote their scalar inputs to vector type.
if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType())
- return CheckVectorOperands(Loc, lex, rex);
+ return CheckVectorOperands(lex, rex, Loc, isCompAssign);
// Shifts don't perform usual arithmetic conversions, they just do integer
// promotions on each operand. C99 6.5.7p3
@@ -7720,7 +6284,8 @@ QualType Sema::CheckCompareOperands(ExprResult &lex, ExprResult &rex, SourceLoca
// comparisons of member pointers to null pointer constants.
if (RHSIsNull &&
((lType->isAnyPointerType() || lType->isNullPtrType()) ||
- (!isRelational && lType->isMemberPointerType()))) {
+ (!isRelational &&
+ (lType->isMemberPointerType() || lType->isBlockPointerType())))) {
rex = ImpCastExprToType(rex.take(), lType,
lType->isMemberPointerType()
? CK_NullToMemberPointer
@@ -7729,7 +6294,8 @@ QualType Sema::CheckCompareOperands(ExprResult &lex, ExprResult &rex, SourceLoca
}
if (LHSIsNull &&
((rType->isAnyPointerType() || rType->isNullPtrType()) ||
- (!isRelational && rType->isMemberPointerType()))) {
+ (!isRelational &&
+ (rType->isMemberPointerType() || rType->isBlockPointerType())))) {
lex = ImpCastExprToType(lex.take(), rType,
rType->isMemberPointerType()
? CK_NullToMemberPointer
@@ -7894,7 +6460,7 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &lex, ExprResult &rex,
bool isRelational) {
// Check to make sure we're operating on vectors of the same type and width,
// Allowing one side to be a scalar of element type.
- QualType vType = CheckVectorOperands(Loc, lex, rex);
+ QualType vType = CheckVectorOperands(lex, rex, Loc, /*isCompAssign*/false);
if (vType.isNull())
return vType;
@@ -7949,7 +6515,7 @@ inline QualType Sema::CheckBitwiseOperands(
if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) {
if (lex.get()->getType()->hasIntegerRepresentation() &&
rex.get()->getType()->hasIntegerRepresentation())
- return CheckVectorOperands(Loc, lex, rex);
+ return CheckVectorOperands(lex, rex, Loc, isCompAssign);
return InvalidOperands(Loc, lex, rex);
}
@@ -7975,8 +6541,8 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
// is a constant.
if (lex.get()->getType()->isIntegerType() && !lex.get()->getType()->isBooleanType() &&
rex.get()->getType()->isIntegerType() && !rex.get()->isValueDependent() &&
- // Don't warn in macros.
- !Loc.isMacroID()) {
+ // Don't warn in macros or template instantiations.
+ !Loc.isMacroID() && ActiveTemplateInstantiations.empty()) {
// If the RHS can be constant folded, and if it constant folds to something
// that isn't 0 or 1 (which indicate a potential logical operation that
// happened to fold to true/false) then warn.
@@ -8099,7 +6665,43 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
unsigned Diag = 0;
bool NeedType = false;
switch (IsLV) { // C99 6.5.16p2
- case Expr::MLV_ConstQualified: Diag = diag::err_typecheck_assign_const; break;
+ case Expr::MLV_ConstQualified:
+ Diag = diag::err_typecheck_assign_const;
+
+ // In ARC, use some specialized diagnostics for occasions where we
+ // infer 'const'. These are always pseudo-strong variables.
+ if (S.getLangOptions().ObjCAutoRefCount) {
+ DeclRefExpr *declRef = dyn_cast<DeclRefExpr>(E->IgnoreParenCasts());
+ if (declRef && isa<VarDecl>(declRef->getDecl())) {
+ VarDecl *var = cast<VarDecl>(declRef->getDecl());
+
+ // Use the normal diagnostic if it's pseudo-__strong but the
+ // user actually wrote 'const'.
+ if (var->isARCPseudoStrong() &&
+ (!var->getTypeSourceInfo() ||
+ !var->getTypeSourceInfo()->getType().isConstQualified())) {
+ // There are two pseudo-strong cases:
+ // - self
+ ObjCMethodDecl *method = S.getCurMethodDecl();
+ if (method && var == method->getSelfDecl())
+ Diag = diag::err_typecheck_arr_assign_self;
+
+ // - fast enumeration variables
+ else
+ Diag = diag::err_typecheck_arr_assign_enumeration;
+
+ SourceRange Assign;
+ if (Loc != OrigLoc)
+ Assign = SourceRange(OrigLoc, OrigLoc);
+ S.Diag(Loc, Diag) << E->getSourceRange() << Assign;
+ // We need to preserve the AST regardless, so migration tool
+ // can do its job.
+ return false;
+ }
+ }
+ }
+
+ break;
case Expr::MLV_ArrayType:
Diag = diag::err_typecheck_array_not_modifiable_lvalue;
NeedType = true;
@@ -8214,6 +6816,13 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, ExprResult &RHS,
<< SourceRange(UO->getOperatorLoc(), UO->getOperatorLoc());
}
}
+
+ if (ConvTy == Compatible) {
+ if (LHSType.getObjCLifetime() == Qualifiers::OCL_Strong)
+ checkRetainCycles(LHS, RHS.get());
+ else if (getLangOptions().ObjCAutoRefCount)
+ checkUnsafeExprAssigns(Loc, LHS, RHS.get());
+ }
} else {
// Compound assignment "x += y"
ConvTy = CheckAssignmentConstraints(Loc, LHSType, RHSType);
@@ -8295,29 +6904,9 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op,
QualType PointeeTy = ResType->getPointeeType();
// C99 6.5.2.4p2, 6.5.6p2
- if (PointeeTy->isVoidType()) {
- if (S.getLangOptions().CPlusPlus) {
- S.Diag(OpLoc, diag::err_typecheck_pointer_arith_void_type)
- << Op->getSourceRange();
- return QualType();
- }
-
- // Pointer to void is a GNU extension in C.
- S.Diag(OpLoc, diag::ext_gnu_void_ptr) << Op->getSourceRange();
- } else if (PointeeTy->isFunctionType()) {
- if (S.getLangOptions().CPlusPlus) {
- S.Diag(OpLoc, diag::err_typecheck_pointer_arith_function_type)
- << Op->getType() << Op->getSourceRange();
- return QualType();
- }
-
- S.Diag(OpLoc, diag::ext_gnu_ptr_func_arith)
- << ResType << Op->getSourceRange();
- } else if (S.RequireCompleteType(OpLoc, PointeeTy,
- S.PDiag(diag::err_typecheck_arithmetic_incomplete_type)
- << Op->getSourceRange()
- << ResType))
+ if (!checkArithmeticOpPointerOperand(S, OpLoc, Op))
return QualType();
+
// Diagnose bad cases where we step over interface counts.
else if (PointeeTy->isObjCObjectType() && S.LangOpts.ObjCNonFragileABI) {
S.Diag(OpLoc, diag::err_arithmetic_nonfragile_interface)
@@ -8400,6 +6989,8 @@ void Sema::ConvertPropertyForLValue(ExprResult &LHS, ExprResult &RHS, QualType &
LHS.get()->getObjectKind() == OK_ObjCProperty);
const ObjCPropertyRefExpr *PropRef = LHS.get()->getObjCProperty();
+ bool Consumed = false;
+
if (PropRef->isImplicitProperty()) {
// If using property-dot syntax notation for assignment, and there is a
// setter, RHS expression is being passed to the setter argument. So,
@@ -8407,6 +6998,8 @@ void Sema::ConvertPropertyForLValue(ExprResult &LHS, ExprResult &RHS, QualType &
if (const ObjCMethodDecl *SetterMD = PropRef->getImplicitPropertySetter()) {
ObjCMethodDecl::param_iterator P = SetterMD->param_begin();
LHSTy = (*P)->getType();
+ Consumed = (getLangOptions().ObjCAutoRefCount &&
+ (*P)->hasAttr<NSConsumedAttr>());
// Otherwise, if the getter returns an l-value, just call that.
} else {
@@ -8418,14 +7011,26 @@ void Sema::ConvertPropertyForLValue(ExprResult &LHS, ExprResult &RHS, QualType &
return;
}
}
+ } else if (getLangOptions().ObjCAutoRefCount) {
+ const ObjCMethodDecl *setter
+ = PropRef->getExplicitProperty()->getSetterMethodDecl();
+ if (setter) {
+ ObjCMethodDecl::param_iterator P = setter->param_begin();
+ LHSTy = (*P)->getType();
+ Consumed = (*P)->hasAttr<NSConsumedAttr>();
+ }
}
- if (getLangOptions().CPlusPlus && LHSTy->isRecordType()) {
+ if ((getLangOptions().CPlusPlus && LHSTy->isRecordType()) ||
+ getLangOptions().ObjCAutoRefCount) {
InitializedEntity Entity =
- InitializedEntity::InitializeParameter(Context, LHSTy);
+ InitializedEntity::InitializeParameter(Context, LHSTy, Consumed);
ExprResult ArgE = PerformCopyInitialization(Entity, SourceLocation(), RHS);
- if (!ArgE.isInvalid())
+ if (!ArgE.isInvalid()) {
RHS = ArgE;
+ if (getLangOptions().ObjCAutoRefCount && !PropRef->isSuperReceiver())
+ checkRetainCycles(const_cast<Expr*>(PropRef->getBase()), RHS.get());
+ }
}
}
@@ -8682,8 +7287,7 @@ static QualType CheckIndirectionOperand(Sema &S, Expr *Op, ExprValueKind &VK,
VK = VK_LValue;
// ...except that certain expressions are never l-values in C.
- if (!S.getLangOptions().CPlusPlus &&
- IsCForbiddenLValueType(S.Context, Result))
+ if (!S.getLangOptions().CPlusPlus && Result.isCForbiddenLValueType())
VK = VK_RValue;
return Result;
@@ -8815,6 +7419,53 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
rhs = move(resolvedRHS);
}
+ // The canonical way to check for a GNU null is with isNullPointerConstant,
+ // but we use a bit of a hack here for speed; this is a relatively
+ // hot path, and isNullPointerConstant is slow.
+ bool LeftNull = isa<GNUNullExpr>(lhs.get()->IgnoreParenImpCasts());
+ bool RightNull = isa<GNUNullExpr>(rhs.get()->IgnoreParenImpCasts());
+
+ // Detect when a NULL constant is used improperly in an expression. These
+ // are mainly cases where the null pointer is used as an integer instead
+ // of a pointer.
+ if (LeftNull || RightNull) {
+ // Avoid analyzing cases where the result will either be invalid (and
+ // diagnosed as such) or entirely valid and not something to warn about.
+ QualType LeftType = lhs.get()->getType();
+ QualType RightType = rhs.get()->getType();
+ if (!LeftType->isBlockPointerType() && !LeftType->isMemberPointerType() &&
+ !LeftType->isFunctionType() &&
+ !RightType->isBlockPointerType() &&
+ !RightType->isMemberPointerType() &&
+ !RightType->isFunctionType()) {
+ if (Opc == BO_Mul || Opc == BO_Div || Opc == BO_Rem || Opc == BO_Add ||
+ Opc == BO_Sub || Opc == BO_Shl || Opc == BO_Shr || Opc == BO_And ||
+ Opc == BO_Xor || Opc == BO_Or || Opc == BO_MulAssign ||
+ Opc == BO_DivAssign || Opc == BO_AddAssign || Opc == BO_SubAssign ||
+ Opc == BO_RemAssign || Opc == BO_ShlAssign || Opc == BO_ShrAssign ||
+ Opc == BO_AndAssign || Opc == BO_OrAssign || Opc == BO_XorAssign) {
+ // These are the operations that would not make sense with a null pointer
+ // no matter what the other expression is.
+ Diag(OpLoc, diag::warn_null_in_arithmetic_operation)
+ << (LeftNull ? lhs.get()->getSourceRange() : SourceRange())
+ << (RightNull ? rhs.get()->getSourceRange() : SourceRange());
+ } else if (Opc == BO_LE || Opc == BO_LT || Opc == BO_GE || Opc == BO_GT ||
+ Opc == BO_EQ || Opc == BO_NE) {
+ // These are the operations that would not make sense with a null pointer
+ // if the other expression the other expression is not a pointer.
+ if (LeftNull != RightNull &&
+ !LeftType->isAnyPointerType() &&
+ !LeftType->canDecayToPointerType() &&
+ !RightType->isAnyPointerType() &&
+ !RightType->canDecayToPointerType()) {
+ Diag(OpLoc, diag::warn_null_in_arithmetic_operation)
+ << (LeftNull ? lhs.get()->getSourceRange()
+ : rhs.get()->getSourceRange());
+ }
+ }
+ }
+ }
+
switch (Opc) {
case BO_Assign:
ResultTy = CheckAssignmentOperands(lhs.get(), rhs, OpLoc, QualType());
@@ -8953,28 +7604,46 @@ static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperatorKind Opc,
(BinOp::isComparisonOp(rhsopc) || BinOp::isBitwiseOp(rhsopc)))
return;
- if (BinOp::isComparisonOp(lhsopc))
+ if (BinOp::isComparisonOp(lhsopc)) {
+ Self.Diag(OpLoc, diag::warn_precedence_bitwise_rel)
+ << SourceRange(lhs->getLocStart(), OpLoc)
+ << BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(lhsopc);
SuggestParentheses(Self, OpLoc,
- Self.PDiag(diag::warn_precedence_bitwise_rel)
- << SourceRange(lhs->getLocStart(), OpLoc)
- << BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(lhsopc),
Self.PDiag(diag::note_precedence_bitwise_silence)
<< BinOp::getOpcodeStr(lhsopc),
- lhs->getSourceRange(),
+ lhs->getSourceRange());
+ SuggestParentheses(Self, OpLoc,
Self.PDiag(diag::note_precedence_bitwise_first)
<< BinOp::getOpcodeStr(Opc),
SourceRange(cast<BinOp>(lhs)->getRHS()->getLocStart(), rhs->getLocEnd()));
- else if (BinOp::isComparisonOp(rhsopc))
+ } else if (BinOp::isComparisonOp(rhsopc)) {
+ Self.Diag(OpLoc, diag::warn_precedence_bitwise_rel)
+ << SourceRange(OpLoc, rhs->getLocEnd())
+ << BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(rhsopc);
SuggestParentheses(Self, OpLoc,
- Self.PDiag(diag::warn_precedence_bitwise_rel)
- << SourceRange(OpLoc, rhs->getLocEnd())
- << BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(rhsopc),
Self.PDiag(diag::note_precedence_bitwise_silence)
<< BinOp::getOpcodeStr(rhsopc),
- rhs->getSourceRange(),
+ rhs->getSourceRange());
+ SuggestParentheses(Self, OpLoc,
Self.PDiag(diag::note_precedence_bitwise_first)
<< BinOp::getOpcodeStr(Opc),
- SourceRange(lhs->getLocEnd(), cast<BinOp>(rhs)->getLHS()->getLocStart()));
+ SourceRange(lhs->getLocStart(),
+ cast<BinOp>(rhs)->getLHS()->getLocStart()));
+ }
+}
+
+/// \brief It accepts a '&' expr that is inside a '|' one.
+/// Emit a diagnostic together with a fixit hint that wraps the '&' expression
+/// in parentheses.
+static void
+EmitDiagnosticForBitwiseAndInBitwiseOr(Sema &Self, SourceLocation OpLoc,
+ BinaryOperator *Bop) {
+ assert(Bop->getOpcode() == BO_And);
+ Self.Diag(Bop->getOperatorLoc(), diag::warn_bitwise_and_in_bitwise_or)
+ << Bop->getSourceRange() << OpLoc;
+ SuggestParentheses(Self, Bop->getOperatorLoc(),
+ Self.PDiag(diag::note_bitwise_and_in_bitwise_or_silence),
+ Bop->getSourceRange());
}
/// \brief It accepts a '&&' expr that is inside a '||' one.
@@ -8984,12 +7653,11 @@ static void
EmitDiagnosticForLogicalAndInLogicalOr(Sema &Self, SourceLocation OpLoc,
BinaryOperator *Bop) {
assert(Bop->getOpcode() == BO_LAnd);
+ Self.Diag(Bop->getOperatorLoc(), diag::warn_logical_and_in_logical_or)
+ << Bop->getSourceRange() << OpLoc;
SuggestParentheses(Self, Bop->getOperatorLoc(),
- Self.PDiag(diag::warn_logical_and_in_logical_or)
- << Bop->getSourceRange() << OpLoc,
Self.PDiag(diag::note_logical_and_in_logical_or_silence),
- Bop->getSourceRange(),
- Self.PDiag(0), SourceRange());
+ Bop->getSourceRange());
}
/// \brief Returns true if the given expression can be evaluated as a constant
@@ -9043,13 +7711,28 @@ static void DiagnoseLogicalAndInLogicalOrRHS(Sema &S, SourceLocation OpLoc,
}
}
+/// \brief Look for '&' in the left or right hand of a '|' expr.
+static void DiagnoseBitwiseAndInBitwiseOr(Sema &S, SourceLocation OpLoc,
+ Expr *OrArg) {
+ if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(OrArg)) {
+ if (Bop->getOpcode() == BO_And)
+ return EmitDiagnosticForBitwiseAndInBitwiseOr(S, OpLoc, Bop);
+ }
+}
+
/// DiagnoseBinOpPrecedence - Emit warnings for expressions with tricky
/// precedence.
static void DiagnoseBinOpPrecedence(Sema &Self, BinaryOperatorKind Opc,
SourceLocation OpLoc, Expr *lhs, Expr *rhs){
// Diagnose "arg1 'bitwise' arg2 'eq' arg3".
if (BinaryOperator::isBitwiseOp(Opc))
- return DiagnoseBitwisePrecedence(Self, Opc, OpLoc, lhs, rhs);
+ DiagnoseBitwisePrecedence(Self, Opc, OpLoc, lhs, rhs);
+
+ // Diagnose "arg1 & arg2 | arg3"
+ if (Opc == BO_Or && !OpLoc.isMacroID()/* Don't warn in macros. */) {
+ DiagnoseBitwiseAndInBitwiseOr(Self, OpLoc, lhs);
+ DiagnoseBitwiseAndInBitwiseOr(Self, OpLoc, rhs);
+ }
// Warn about arg1 || arg2 && arg3, as GCC 4.3+ does.
// We don't warn for 'assert(a || b && "bad")' since this is safe.
@@ -9274,6 +7957,29 @@ ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc,
Context.getPointerType(Context.VoidTy)));
}
+/// Given the last statement in a statement-expression, check whether
+/// the result is a producing expression (like a call to an
+/// ns_returns_retained function) and, if so, rebuild it to hoist the
+/// release out of the full-expression. Otherwise, return null.
+/// Cannot fail.
+static Expr *maybeRebuildARCConsumingStmt(Stmt *s) {
+ // Should always be wrapped with one of these.
+ ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(s);
+ if (!cleanups) return 0;
+
+ ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(cleanups->getSubExpr());
+ if (!cast || cast->getCastKind() != CK_ObjCConsumeObject)
+ return 0;
+
+ // Splice out the cast. This shouldn't modify any interesting
+ // features of the statement.
+ Expr *producer = cast->getSubExpr();
+ assert(producer->getType() == cast->getType());
+ assert(producer->getValueKind() == cast->getValueKind());
+ cleanups->setSubExpr(producer);
+ return cleanups;
+}
+
ExprResult
Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt,
SourceLocation RPLoc) { // "({..})"
@@ -9301,6 +8007,7 @@ Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt,
LastLabelStmt = Label;
LastStmt = Label->getSubStmt();
}
+
if (Expr *LastE = dyn_cast<Expr>(LastStmt)) {
// Do function/array conversion on the last expression, but not
// lvalue-to-rvalue. However, initialize an unqualified type.
@@ -9310,12 +8017,24 @@ Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt,
Ty = LastExpr.get()->getType().getUnqualifiedType();
if (!Ty->isDependentType() && !LastExpr.get()->isTypeDependent()) {
- LastExpr = PerformCopyInitialization(
+ // In ARC, if the final expression ends in a consume, splice
+ // the consume out and bind it later. In the alternate case
+ // (when dealing with a retainable type), the result
+ // initialization will create a produce. In both cases the
+ // result will be +1, and we'll need to balance that out with
+ // a bind.
+ if (Expr *rebuiltLastStmt
+ = maybeRebuildARCConsumingStmt(LastExpr.get())) {
+ LastExpr = rebuiltLastStmt;
+ } else {
+ LastExpr = PerformCopyInitialization(
InitializedEntity::InitializeResult(LPLoc,
Ty,
false),
SourceLocation(),
- LastExpr);
+ LastExpr);
+ }
+
if (LastExpr.isInvalid())
return ExprError();
if (LastExpr.get() != 0) {
@@ -9757,7 +8476,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
// If we don't have a function type, just build one from nothing.
} else {
FunctionProtoType::ExtProtoInfo EPI;
- EPI.ExtInfo = FunctionType::ExtInfo(NoReturn, false, 0, CC_Default);
+ EPI.ExtInfo = FunctionType::ExtInfo().withNoReturn(NoReturn);
BlockTy = Context.getFunctionType(RetTy, 0, 0, EPI);
}
@@ -9766,15 +8485,25 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
BlockTy = Context.getBlockPointerType(BlockTy);
// If needed, diagnose invalid gotos and switches in the block.
- if (getCurFunction()->NeedsScopeChecking() && !hasAnyErrorsInThisFunction())
+ if (getCurFunction()->NeedsScopeChecking() &&
+ !hasAnyUnrecoverableErrorsInThisFunction())
DiagnoseInvalidJumps(cast<CompoundStmt>(Body));
BSI->TheDecl->setBody(cast<CompoundStmt>(Body));
- BlockExpr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy);
+ for (BlockDecl::capture_const_iterator ci = BSI->TheDecl->capture_begin(),
+ ce = BSI->TheDecl->capture_end(); ci != ce; ++ci) {
+ const VarDecl *variable = ci->getVariable();
+ QualType T = variable->getType();
+ QualType::DestructionKind destructKind = T.isDestructedType();
+ if (destructKind != QualType::DK_none)
+ getCurFunction()->setHasBranchProtectedScope();
+ }
+ BlockExpr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy);
const AnalysisBasedWarnings::Policy &WP = AnalysisWarnings.getDefaultPolicy();
PopFunctionOrBlockScope(&WP, Result->getBlockDecl(), Result);
+
return Owned(Result);
}
@@ -9818,8 +8547,41 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc,
<< OrigExpr->getType() << E->getSourceRange());
}
- // FIXME: Check that type is complete/non-abstract
- // FIXME: Warn if a non-POD type is passed in.
+ if (!TInfo->getType()->isDependentType()) {
+ if (RequireCompleteType(TInfo->getTypeLoc().getBeginLoc(), TInfo->getType(),
+ PDiag(diag::err_second_parameter_to_va_arg_incomplete)
+ << TInfo->getTypeLoc().getSourceRange()))
+ return ExprError();
+
+ if (RequireNonAbstractType(TInfo->getTypeLoc().getBeginLoc(),
+ TInfo->getType(),
+ PDiag(diag::err_second_parameter_to_va_arg_abstract)
+ << TInfo->getTypeLoc().getSourceRange()))
+ return ExprError();
+
+ if (!TInfo->getType().isPODType(Context))
+ Diag(TInfo->getTypeLoc().getBeginLoc(),
+ diag::warn_second_parameter_to_va_arg_not_pod)
+ << TInfo->getType()
+ << TInfo->getTypeLoc().getSourceRange();
+
+ // Check for va_arg where arguments of the given type will be promoted
+ // (i.e. this va_arg is guaranteed to have undefined behavior).
+ QualType PromoteType;
+ if (TInfo->getType()->isPromotableIntegerType()) {
+ PromoteType = Context.getPromotedIntegerType(TInfo->getType());
+ if (Context.typesAreCompatible(PromoteType, TInfo->getType()))
+ PromoteType = QualType();
+ }
+ if (TInfo->getType()->isSpecificBuiltinType(BuiltinType::Float))
+ PromoteType = Context.DoubleTy;
+ if (!PromoteType.isNull())
+ Diag(TInfo->getTypeLoc().getBeginLoc(),
+ diag::warn_second_parameter_to_va_arg_never_compatible)
+ << TInfo->getType()
+ << PromoteType
+ << TInfo->getTypeLoc().getSourceRange();
+ }
QualType T = TInfo->getType().getNonLValueExprType(Context);
return Owned(new (Context) VAArgExpr(BuiltinLoc, E, TInfo, RPLoc, T));
@@ -9913,6 +8675,11 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
if (lhq.getAddressSpace() != rhq.getAddressSpace()) {
DiagKind = diag::err_typecheck_incompatible_address_space;
break;
+
+
+ } else if (lhq.getObjCLifetime() != rhq.getObjCLifetime()) {
+ DiagKind = diag::err_typecheck_incompatible_ownership;
+ break;
}
llvm_unreachable("unknown error case for discarding qualifiers!");
@@ -9950,6 +8717,9 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
case IncompatibleVectors:
DiagKind = diag::warn_incompatible_vectors;
break;
+ case IncompatibleObjCWeakRef:
+ DiagKind = diag::err_arc_weak_unavailable_assign;
+ break;
case Incompatible:
DiagKind = diag::err_typecheck_convert_incompatible;
isInvalid = true;
@@ -10027,7 +8797,10 @@ bool Sema::VerifyIntegerConstantExpression(const Expr *E, llvm::APSInt *Result){
void
Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext) {
ExprEvalContexts.push_back(
- ExpressionEvaluationContextRecord(NewContext, ExprTemporaries.size()));
+ ExpressionEvaluationContextRecord(NewContext,
+ ExprTemporaries.size(),
+ ExprNeedsCleanups));
+ ExprNeedsCleanups = false;
}
void
@@ -10062,15 +8835,27 @@ Sema::PopExpressionEvaluationContext() {
// temporaries that we may have created as part of the evaluation of
// the expression in that context: they aren't relevant because they
// will never be constructed.
- if (Rec.Context == Unevaluated &&
- ExprTemporaries.size() > Rec.NumTemporaries)
+ if (Rec.Context == Unevaluated) {
ExprTemporaries.erase(ExprTemporaries.begin() + Rec.NumTemporaries,
ExprTemporaries.end());
+ ExprNeedsCleanups = Rec.ParentNeedsCleanups;
+
+ // Otherwise, merge the contexts together.
+ } else {
+ ExprNeedsCleanups |= Rec.ParentNeedsCleanups;
+ }
// Destroy the popped expression evaluation record.
Rec.Destroy();
}
+void Sema::DiscardCleanupsInEvaluationContext() {
+ ExprTemporaries.erase(
+ ExprTemporaries.begin() + ExprEvalContexts.back().NumTemporaries,
+ ExprTemporaries.end());
+ ExprNeedsCleanups = false;
+}
+
/// \brief Note that the given declaration was referenced in the source code.
///
/// This routine should be invoke whenever a given declaration is referenced
@@ -10364,7 +9149,7 @@ void Sema::MarkDeclarationsReferencedInExpr(Expr *E) {
/// during overload resolution or within sizeof/alignof/typeof/typeid.
bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *stmt,
const PartialDiagnostic &PD) {
- switch (ExprEvalContexts.back().Context ) {
+ switch (ExprEvalContexts.back().Context) {
case Unevaluated:
// The argument will never be evaluated, so don't complain.
break;
@@ -10780,9 +9565,6 @@ ExprResult RebuildUnknownAnyExpr::VisitCallExpr(CallExpr *call) {
}
ExprResult RebuildUnknownAnyExpr::VisitObjCMessageExpr(ObjCMessageExpr *msg) {
- ObjCMethodDecl *method = msg->getMethodDecl();
- assert(method && "__unknown_anytype message without result type?");
-
// Verify that this is a legal result type of a call.
if (DestType->isArrayType() || DestType->isFunctionType()) {
S.Diag(msg->getExprLoc(), diag::err_func_returning_array_function)
@@ -10790,8 +9572,11 @@ ExprResult RebuildUnknownAnyExpr::VisitObjCMessageExpr(ObjCMessageExpr *msg) {
return ExprError();
}
- assert(method->getResultType() == S.Context.UnknownAnyTy);
- method->setResultType(DestType);
+ // Rewrite the method result type if available.
+ if (ObjCMethodDecl *method = msg->getMethodDecl()) {
+ assert(method->getResultType() == S.Context.UnknownAnyTy);
+ method->setResultType(DestType);
+ }
// Change the type of the message.
msg->setType(DestType.getNonReferenceType());
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 2f5a890e51de..e804fcd60c74 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -480,23 +480,63 @@ Sema::ActOnCXXNullPtrLiteral(SourceLocation Loc) {
/// ActOnCXXThrow - Parse throw expressions.
ExprResult
-Sema::ActOnCXXThrow(SourceLocation OpLoc, Expr *Ex) {
+Sema::ActOnCXXThrow(Scope *S, SourceLocation OpLoc, Expr *Ex) {
+ bool IsThrownVarInScope = false;
+ if (Ex) {
+ // C++0x [class.copymove]p31:
+ // When certain criteria are met, an implementation is allowed to omit the
+ // copy/move construction of a class object [...]
+ //
+ // - in a throw-expression, when the operand is the name of a
+ // non-volatile automatic object (other than a function or catch-
+ // clause parameter) whose scope does not extend beyond the end of the
+ // innermost enclosing try-block (if there is one), the copy/move
+ // operation from the operand to the exception object (15.1) can be
+ // omitted by constructing the automatic object directly into the
+ // exception object
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Ex->IgnoreParens()))
+ if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
+ if (Var->hasLocalStorage() && !Var->getType().isVolatileQualified()) {
+ for( ; S; S = S->getParent()) {
+ if (S->isDeclScope(Var)) {
+ IsThrownVarInScope = true;
+ break;
+ }
+
+ if (S->getFlags() &
+ (Scope::FnScope | Scope::ClassScope | Scope::BlockScope |
+ Scope::FunctionPrototypeScope | Scope::ObjCMethodScope |
+ Scope::TryScope))
+ break;
+ }
+ }
+ }
+ }
+
+ return BuildCXXThrow(OpLoc, Ex, IsThrownVarInScope);
+}
+
+ExprResult Sema::BuildCXXThrow(SourceLocation OpLoc, Expr *Ex,
+ bool IsThrownVarInScope) {
// Don't report an error if 'throw' is used in system headers.
if (!getLangOptions().CXXExceptions &&
!getSourceManager().isInSystemHeader(OpLoc))
Diag(OpLoc, diag::err_exceptions_disabled) << "throw";
-
+
if (Ex && !Ex->isTypeDependent()) {
- ExprResult ExRes = CheckCXXThrowOperand(OpLoc, Ex);
+ ExprResult ExRes = CheckCXXThrowOperand(OpLoc, Ex, IsThrownVarInScope);
if (ExRes.isInvalid())
return ExprError();
Ex = ExRes.take();
}
- return Owned(new (Context) CXXThrowExpr(Ex, Context.VoidTy, OpLoc));
+
+ return Owned(new (Context) CXXThrowExpr(Ex, Context.VoidTy, OpLoc,
+ IsThrownVarInScope));
}
/// CheckCXXThrowOperand - Validate the operand of a throw.
-ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E) {
+ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E,
+ bool IsThrownVarInScope) {
// C++ [except.throw]p3:
// A throw-expression initializes a temporary object, called the exception
// object, the type of which is determined by removing any top-level
@@ -535,14 +575,28 @@ ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E) {
// Initialize the exception result. This implicitly weeds out
// abstract types or types with inaccessible copy constructors.
- const VarDecl *NRVOVariable = getCopyElisionCandidate(QualType(), E, false);
-
- // FIXME: Determine whether we can elide this copy per C++0x [class.copy]p32.
+
+ // C++0x [class.copymove]p31:
+ // When certain criteria are met, an implementation is allowed to omit the
+ // copy/move construction of a class object [...]
+ //
+ // - in a throw-expression, when the operand is the name of a
+ // non-volatile automatic object (other than a function or catch-clause
+ // parameter) whose scope does not extend beyond the end of the
+ // innermost enclosing try-block (if there is one), the copy/move
+ // operation from the operand to the exception object (15.1) can be
+ // omitted by constructing the automatic object directly into the
+ // exception object
+ const VarDecl *NRVOVariable = 0;
+ if (IsThrownVarInScope)
+ NRVOVariable = getCopyElisionCandidate(QualType(), E, false);
+
InitializedEntity Entity =
InitializedEntity::InitializeException(ThrowLoc, E->getType(),
- /*NRVO=*/false);
+ /*NRVO=*/NRVOVariable != 0);
Res = PerformMoveOrCopyInitialization(Entity, NRVOVariable,
- QualType(), E);
+ QualType(), E,
+ IsThrownVarInScope);
if (Res.isInvalid())
return ExprError();
E = Res.take();
@@ -691,7 +745,8 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
ExprValueKind VK = VK_RValue;
CXXCastPath BasePath;
ExprResult CastExpr =
- CheckCastTypes(TInfo->getTypeLoc().getSourceRange(), Ty, Exprs[0],
+ CheckCastTypes(TInfo->getTypeLoc().getBeginLoc(),
+ TInfo->getTypeLoc().getSourceRange(), Ty, Exprs[0],
Kind, VK, BasePath,
/*FunctionalStyle=*/true);
if (CastExpr.isInvalid())
@@ -827,8 +882,7 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
}
}
- TypeSourceInfo *TInfo = GetTypeForDeclarator(D, /*Scope=*/0, /*OwnedDecl=*/0,
- /*AllowAuto=*/true);
+ TypeSourceInfo *TInfo = GetTypeForDeclarator(D, /*Scope=*/0);
QualType AllocType = TInfo->getType();
if (D.isInvalidType())
return ExprError();
@@ -902,8 +956,16 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
if (CheckAllocatedType(AllocType, TypeRange.getBegin(), TypeRange))
return ExprError();
- QualType ResultType = Context.getPointerType(AllocType);
+ // In ARC, infer 'retaining' for the allocated
+ if (getLangOptions().ObjCAutoRefCount &&
+ AllocType.getObjCLifetime() == Qualifiers::OCL_None &&
+ AllocType->isObjCLifetimeType()) {
+ AllocType = Context.getLifetimeQualifiedType(AllocType,
+ AllocType->getObjCARCImplicitLifetime());
+ }
+ QualType ResultType = Context.getPointerType(AllocType);
+
// C++ 5.3.4p6: "The expression in a direct-new-declarator shall have integral
// or enumeration type with a non-negative value."
if (ArraySize && !ArraySize->isTypeDependent()) {
@@ -964,6 +1026,14 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
}
}
+ // ARC: warn about ABI issues.
+ if (getLangOptions().ObjCAutoRefCount) {
+ QualType BaseAllocType = Context.getBaseElementType(AllocType);
+ if (BaseAllocType.hasStrongOrWeakObjCLifetime())
+ Diag(StartLoc, diag::warn_err_new_delete_object_array)
+ << 0 << BaseAllocType;
+ }
+
// Note that we do *not* convert the argument in any way. It can
// be signed, larger than size_t, whatever.
}
@@ -1078,7 +1148,17 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
if (OperatorDelete)
MarkDeclarationReferenced(StartLoc, OperatorDelete);
- // FIXME: Also check that the destructor is accessible. (C++ 5.3.4p16)
+ // C++0x [expr.new]p17:
+ // If the new expression creates an array of objects of class type,
+ // access and ambiguity control are done for the destructor.
+ if (ArraySize && Constructor) {
+ if (CXXDestructorDecl *dtor = LookupDestructor(Constructor->getParent())) {
+ MarkDeclarationReferenced(StartLoc, dtor);
+ CheckDestructorAccess(StartLoc, dtor,
+ PDiag(diag::err_access_dtor)
+ << Context.getBaseElementType(AllocType));
+ }
+ }
PlacementArgs.release();
ConstructorArgs.release();
@@ -1122,6 +1202,15 @@ bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc,
else if (unsigned AddressSpace = AllocType.getAddressSpace())
return Diag(Loc, diag::err_address_space_qualified_new)
<< AllocType.getUnqualifiedType() << AddressSpace;
+ else if (getLangOptions().ObjCAutoRefCount) {
+ if (const ArrayType *AT = Context.getAsArrayType(AllocType)) {
+ QualType BaseAllocType = Context.getBaseElementType(AT);
+ if (BaseAllocType.getObjCLifetime() == Qualifiers::OCL_None &&
+ BaseAllocType->isObjCLifetimeType())
+ return Diag(Loc, diag::err_arc_new_array_without_ownership)
+ << BaseAllocType;
+ }
+ }
return false;
}
@@ -1774,8 +1863,9 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
// delete-expression; it is not necessary to cast away the constness
// (5.2.11) of the pointer expression before it is used as the operand
// of the delete-expression. ]
- Ex = ImpCastExprToType(Ex.take(), Context.getPointerType(Context.VoidTy),
- CK_NoOp);
+ if (!Context.hasSameType(Ex.get()->getType(), Context.VoidPtrTy))
+ Ex = Owned(ImplicitCastExpr::Create(Context, Context.VoidPtrTy, CK_NoOp,
+ Ex.take(), 0, VK_RValue));
if (Pointee->isArrayType() && !ArrayForm) {
Diag(StartLoc, diag::warn_delete_array_type)
@@ -1830,6 +1920,14 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
if (!dtor || !dtor->isVirtual())
Diag(StartLoc, diag::warn_delete_non_virtual_dtor) << PointeeElem;
}
+
+ } else if (getLangOptions().ObjCAutoRefCount &&
+ PointeeElem->isObjCLifetimeType() &&
+ (PointeeElem.getObjCLifetime() == Qualifiers::OCL_Strong ||
+ PointeeElem.getObjCLifetime() == Qualifiers::OCL_Weak) &&
+ ArrayForm) {
+ Diag(StartLoc, diag::warn_err_new_delete_object_array)
+ << 1 << PointeeElem;
}
if (!OperatorDelete) {
@@ -1988,11 +2086,12 @@ static ExprResult BuildCXXCastArgument(Sema &S,
ExprResult
Sema::PerformImplicitConversion(Expr *From, QualType ToType,
const ImplicitConversionSequence &ICS,
- AssignmentAction Action, bool CStyle) {
+ AssignmentAction Action,
+ CheckedConversionKind CCK) {
switch (ICS.getKind()) {
case ImplicitConversionSequence::StandardConversion: {
ExprResult Res = PerformImplicitConversion(From, ToType, ICS.Standard,
- Action, CStyle);
+ Action, CCK);
if (Res.isInvalid())
return ExprError();
From = Res.take();
@@ -2027,7 +2126,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
ExprResult Res =
PerformImplicitConversion(From, BeforeToType,
ICS.UserDefined.Before, AA_Converting,
- CStyle);
+ CCK);
if (Res.isInvalid())
return ExprError();
From = Res.take();
@@ -2047,7 +2146,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
From = CastArg.take();
return PerformImplicitConversion(From, ToType, ICS.UserDefined.After,
- AA_Converting, CStyle);
+ AA_Converting, CCK);
}
case ImplicitConversionSequence::AmbiguousConversion:
@@ -2076,13 +2175,16 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
ExprResult
Sema::PerformImplicitConversion(Expr *From, QualType ToType,
const StandardConversionSequence& SCS,
- AssignmentAction Action, bool CStyle) {
+ AssignmentAction Action,
+ CheckedConversionKind CCK) {
+ bool CStyle = (CCK == CCK_CStyleCast || CCK == CCK_FunctionalCast);
+
// Overall FIXME: we are recomputing too many types here and doing far too
// much extra work. What this means is that we need to keep track of more
// information that is computed when we try the implicit conversion initially,
// so that we don't need to recompute anything here.
QualType FromType = From->getType();
-
+
if (SCS.CopyConstructor) {
// FIXME: When can ToType be a reference type?
assert(!ToType->isReferenceType());
@@ -2149,12 +2251,14 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
case ICK_Array_To_Pointer:
FromType = Context.getArrayDecayedType(FromType);
- From = ImpCastExprToType(From, FromType, CK_ArrayToPointerDecay).take();
+ From = ImpCastExprToType(From, FromType, CK_ArrayToPointerDecay,
+ VK_RValue, /*BasePath=*/0, CCK).take();
break;
case ICK_Function_To_Pointer:
FromType = Context.getPointerType(FromType);
- From = ImpCastExprToType(From, FromType, CK_FunctionToPointerDecay).take();
+ From = ImpCastExprToType(From, FromType, CK_FunctionToPointerDecay,
+ VK_RValue, /*BasePath=*/0, CCK).take();
break;
default:
@@ -2178,17 +2282,20 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
if (CheckExceptionSpecCompatibility(From, ToType))
return ExprError();
- From = ImpCastExprToType(From, ToType, CK_NoOp).take();
+ From = ImpCastExprToType(From, ToType, CK_NoOp,
+ VK_RValue, /*BasePath=*/0, CCK).take();
break;
case ICK_Integral_Promotion:
case ICK_Integral_Conversion:
- From = ImpCastExprToType(From, ToType, CK_IntegralCast).take();
+ From = ImpCastExprToType(From, ToType, CK_IntegralCast,
+ VK_RValue, /*BasePath=*/0, CCK).take();
break;
case ICK_Floating_Promotion:
case ICK_Floating_Conversion:
- From = ImpCastExprToType(From, ToType, CK_FloatingCast).take();
+ From = ImpCastExprToType(From, ToType, CK_FloatingCast,
+ VK_RValue, /*BasePath=*/0, CCK).take();
break;
case ICK_Complex_Promotion:
@@ -2206,21 +2313,26 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
} else {
CK = CK_IntegralComplexCast;
}
- From = ImpCastExprToType(From, ToType, CK).take();
+ From = ImpCastExprToType(From, ToType, CK,
+ VK_RValue, /*BasePath=*/0, CCK).take();
break;
}
case ICK_Floating_Integral:
if (ToType->isRealFloatingType())
- From = ImpCastExprToType(From, ToType, CK_IntegralToFloating).take();
+ From = ImpCastExprToType(From, ToType, CK_IntegralToFloating,
+ VK_RValue, /*BasePath=*/0, CCK).take();
else
- From = ImpCastExprToType(From, ToType, CK_FloatingToIntegral).take();
+ From = ImpCastExprToType(From, ToType, CK_FloatingToIntegral,
+ VK_RValue, /*BasePath=*/0, CCK).take();
break;
case ICK_Compatible_Conversion:
- From = ImpCastExprToType(From, ToType, CK_NoOp).take();
+ From = ImpCastExprToType(From, ToType, CK_NoOp,
+ VK_RValue, /*BasePath=*/0, CCK).take();
break;
+ case ICK_Writeback_Conversion:
case ICK_Pointer_Conversion: {
if (SCS.IncompatibleObjC && Action != AA_Casting) {
// Diagnose incompatible Objective-C conversions
@@ -2234,17 +2346,30 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
diag::ext_typecheck_convert_incompatible_pointer)
<< From->getType() << ToType << Action
<< From->getSourceRange();
-
+
if (From->getType()->isObjCObjectPointerType() &&
ToType->isObjCObjectPointerType())
EmitRelatedResultTypeNote(From);
- }
-
+ }
+ else if (getLangOptions().ObjCAutoRefCount &&
+ !CheckObjCARCUnavailableWeakConversion(ToType,
+ From->getType())) {
+ if (Action == AA_Initializing)
+ Diag(From->getSourceRange().getBegin(),
+ diag::err_arc_weak_unavailable_assign);
+ else
+ Diag(From->getSourceRange().getBegin(),
+ diag::err_arc_convesion_of_weak_unavailable)
+ << (Action == AA_Casting) << From->getType() << ToType
+ << From->getSourceRange();
+ }
+
CastKind Kind = CK_Invalid;
CXXCastPath BasePath;
if (CheckPointerConversion(From, ToType, Kind, BasePath, CStyle))
return ExprError();
- From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath).take();
+ From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath, CCK)
+ .take();
break;
}
@@ -2255,13 +2380,15 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
return ExprError();
if (CheckExceptionSpecCompatibility(From, ToType))
return ExprError();
- From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath).take();
+ From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath, CCK)
+ .take();
break;
}
case ICK_Boolean_Conversion:
From = ImpCastExprToType(From, Context.BoolTy,
- ScalarTypeToBooleanCastKind(FromType)).take();
+ ScalarTypeToBooleanCastKind(FromType),
+ VK_RValue, /*BasePath=*/0, CCK).take();
break;
case ICK_Derived_To_Base: {
@@ -2276,16 +2403,18 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
From = ImpCastExprToType(From, ToType.getNonReferenceType(),
CK_DerivedToBase, CastCategory(From),
- &BasePath).take();
+ &BasePath, CCK).take();
break;
}
case ICK_Vector_Conversion:
- From = ImpCastExprToType(From, ToType, CK_BitCast).take();
+ From = ImpCastExprToType(From, ToType, CK_BitCast,
+ VK_RValue, /*BasePath=*/0, CCK).take();
break;
case ICK_Vector_Splat:
- From = ImpCastExprToType(From, ToType, CK_VectorSplat).take();
+ From = ImpCastExprToType(From, ToType, CK_VectorSplat,
+ VK_RValue, /*BasePath=*/0, CCK).take();
break;
case ICK_Complex_Real:
@@ -2321,27 +2450,30 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
// _Complex x -> x
From = ImpCastExprToType(From, ElType,
isFloatingComplex ? CK_FloatingComplexToReal
- : CK_IntegralComplexToReal).take();
+ : CK_IntegralComplexToReal,
+ VK_RValue, /*BasePath=*/0, CCK).take();
// x -> y
if (Context.hasSameUnqualifiedType(ElType, ToType)) {
// do nothing
} else if (ToType->isRealFloatingType()) {
From = ImpCastExprToType(From, ToType,
- isFloatingComplex ? CK_FloatingCast : CK_IntegralToFloating).take();
+ isFloatingComplex ? CK_FloatingCast : CK_IntegralToFloating,
+ VK_RValue, /*BasePath=*/0, CCK).take();
} else {
assert(ToType->isIntegerType());
From = ImpCastExprToType(From, ToType,
- isFloatingComplex ? CK_FloatingToIntegral : CK_IntegralCast).take();
+ isFloatingComplex ? CK_FloatingToIntegral : CK_IntegralCast,
+ VK_RValue, /*BasePath=*/0, CCK).take();
}
}
break;
case ICK_Block_Pointer_Conversion: {
- From = ImpCastExprToType(From, ToType.getUnqualifiedType(), CK_BitCast,
- VK_RValue).take();
- break;
- }
+ From = ImpCastExprToType(From, ToType.getUnqualifiedType(), CK_BitCast,
+ VK_RValue, /*BasePath=*/0, CCK).take();
+ break;
+ }
case ICK_TransparentUnionConversion: {
ExprResult FromRes = Owned(From);
@@ -2376,7 +2508,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
ExprValueKind VK = ToType->isReferenceType() ?
CastCategory(From) : VK_RValue;
From = ImpCastExprToType(From, ToType.getNonLValueExprType(Context),
- CK_NoOp, VK).take();
+ CK_NoOp, VK, /*BasePath=*/0, CCK).take();
if (SCS.DeprecatedStringLiteralToCharPtr &&
!getLangOptions().WritableStrings)
@@ -2553,6 +2685,23 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
case UTT_IsObject:
return T->isObjectType();
case UTT_IsScalar:
+ // Note: semantic analysis depends on Objective-C lifetime types to be
+ // considered scalar types. However, such types do not actually behave
+ // like scalar types at run time (since they may require retain/release
+ // operations), so we report them as non-scalar.
+ if (T->isObjCLifetimeType()) {
+ switch (T.getObjCLifetime()) {
+ case Qualifiers::OCL_None:
+ case Qualifiers::OCL_ExplicitNone:
+ return true;
+
+ case Qualifiers::OCL_Strong:
+ case Qualifiers::OCL_Weak:
+ case Qualifiers::OCL_Autoreleasing:
+ return false;
+ }
+ }
+
return T->isScalarType();
case UTT_IsCompound:
return T->isCompoundType();
@@ -2566,13 +2715,13 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
case UTT_IsVolatile:
return T.isVolatileQualified();
case UTT_IsTrivial:
- return T->isTrivialType();
+ return T.isTrivialType(Self.Context);
case UTT_IsTriviallyCopyable:
- return T->isTriviallyCopyableType();
+ return T.isTriviallyCopyableType(Self.Context);
case UTT_IsStandardLayout:
return T->isStandardLayoutType();
case UTT_IsPOD:
- return T->isPODType();
+ return T.isPODType(Self.Context);
case UTT_IsLiteral:
return T->isLiteralType();
case UTT_IsEmpty:
@@ -2605,7 +2754,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
// If __is_pod (type) is true then the trait is true, else if type is
// a cv class or union type (or array thereof) with a trivial default
// constructor ([class.ctor]) then the trait is true, else it is false.
- if (T->isPODType())
+ if (T.isPODType(Self.Context))
return true;
if (const RecordType *RT =
C.getBaseElementType(T)->getAs<RecordType>())
@@ -2617,7 +2766,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
// the trait is true, else if type is a cv class or union type
// with a trivial copy constructor ([class.copy]) then the trait
// is true, else it is false.
- if (T->isPODType() || T->isReferenceType())
+ if (T.isPODType(Self.Context) || T->isReferenceType())
return true;
if (const RecordType *RT = T->getAs<RecordType>())
return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialCopyConstructor();
@@ -2637,7 +2786,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
if (C.getBaseElementType(T).isConstQualified())
return false;
- if (T->isPODType())
+ if (T.isPODType(Self.Context))
return true;
if (const RecordType *RT = T->getAs<RecordType>())
return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialCopyAssignment();
@@ -2649,8 +2798,14 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
// type (or array thereof) with a trivial destructor
// ([class.dtor]) then the trait is true, else it is
// false.
- if (T->isPODType() || T->isReferenceType())
+ if (T.isPODType(Self.Context) || T->isReferenceType())
+ return true;
+
+ // Objective-C++ ARC: autorelease types don't require destruction.
+ if (T->isObjCLifetimeType() &&
+ T.getObjCLifetime() == Qualifiers::OCL_Autoreleasing)
return true;
+
if (const RecordType *RT =
C.getBaseElementType(T)->getAs<RecordType>())
return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialDestructor();
@@ -2668,8 +2823,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
return false;
if (T->isReferenceType())
return false;
- if (T->isPODType())
- return true;
+ if (T.isPODType(Self.Context) || T->isObjCLifetimeType())
+ return true;
if (const RecordType *RT = T->getAs<RecordType>()) {
CXXRecordDecl* RD = cast<CXXRecordDecl>(RT->getDecl());
if (RD->hasTrivialCopyAssignment())
@@ -2704,7 +2859,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
// if type is a cv class or union type with copy constructors that are
// known not to throw an exception then the trait is true, else it is
// false.
- if (T->isPODType() || T->isReferenceType())
+ if (T.isPODType(C) || T->isReferenceType() || T->isObjCLifetimeType())
return true;
if (const RecordType *RT = T->getAs<RecordType>()) {
CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
@@ -2744,7 +2899,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
// true, else if type is a cv class or union type (or array
// thereof) with a default constructor that is known not to
// throw an exception then the trait is true, else it is false.
- if (T->isPODType())
+ if (T.isPODType(C) || T->isObjCLifetimeType())
return true;
if (const RecordType *RT = C.getBaseElementType(T)->getAs<RecordType>()) {
CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
@@ -3089,6 +3244,20 @@ QualType Sema::CheckPointerToMemberOperands(ExprResult &lex, ExprResult &rex,
ExprValueKind &VK,
SourceLocation Loc,
bool isIndirect) {
+ assert(!lex.get()->getType()->isPlaceholderType() &&
+ !rex.get()->getType()->isPlaceholderType() &&
+ "placeholders should have been weeded out by now");
+
+ // The LHS undergoes lvalue conversions if this is ->*.
+ if (isIndirect) {
+ lex = DefaultLvalueConversion(lex.take());
+ if (lex.isInvalid()) return QualType();
+ }
+
+ // The RHS always undergoes lvalue conversions.
+ rex = DefaultLvalueConversion(rex.take());
+ if (rex.isInvalid()) return QualType();
+
const char *OpSpelling = isIndirect ? "->*" : ".*";
// C++ 5.5p2
// The binary operator .* [p3: ->*] binds its second operand, which shall
@@ -3556,7 +3725,7 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, Ex
// Extension: conditional operator involving vector types.
if (LTy->isVectorType() || RTy->isVectorType())
- return CheckVectorOperands(QuestionLoc, LHS, RHS);
+ return CheckVectorOperands(LHS, RHS, QuestionLoc, /*isCompAssign*/false);
// -- The second and third operands have arithmetic or enumeration type;
// the usual arithmetic conversions are performed to bring them to a
@@ -3828,17 +3997,83 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) {
if (!E)
return ExprError();
- if (!Context.getLangOptions().CPlusPlus)
+ assert(!isa<CXXBindTemporaryExpr>(E) && "Double-bound temporary?");
+
+ // If the result is a glvalue, we shouldn't bind it.
+ if (!E->isRValue())
return Owned(E);
- assert(!isa<CXXBindTemporaryExpr>(E) && "Double-bound temporary?");
+ // In ARC, calls that return a retainable type can return retained,
+ // in which case we have to insert a consuming cast.
+ if (getLangOptions().ObjCAutoRefCount &&
+ E->getType()->isObjCRetainableType()) {
+
+ bool ReturnsRetained;
+
+ // For actual calls, we compute this by examining the type of the
+ // called value.
+ if (CallExpr *Call = dyn_cast<CallExpr>(E)) {
+ Expr *Callee = Call->getCallee()->IgnoreParens();
+ QualType T = Callee->getType();
+
+ if (T == Context.BoundMemberTy) {
+ // Handle pointer-to-members.
+ if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(Callee))
+ T = BinOp->getRHS()->getType();
+ else if (MemberExpr *Mem = dyn_cast<MemberExpr>(Callee))
+ T = Mem->getMemberDecl()->getType();
+ }
+
+ if (const PointerType *Ptr = T->getAs<PointerType>())
+ T = Ptr->getPointeeType();
+ else if (const BlockPointerType *Ptr = T->getAs<BlockPointerType>())
+ T = Ptr->getPointeeType();
+ else if (const MemberPointerType *MemPtr = T->getAs<MemberPointerType>())
+ T = MemPtr->getPointeeType();
+
+ const FunctionType *FTy = T->getAs<FunctionType>();
+ assert(FTy && "call to value not of function type?");
+ ReturnsRetained = FTy->getExtInfo().getProducesResult();
+
+ // ActOnStmtExpr arranges things so that StmtExprs of retainable
+ // type always produce a +1 object.
+ } else if (isa<StmtExpr>(E)) {
+ ReturnsRetained = true;
+
+ // For message sends and property references, we try to find an
+ // actual method. FIXME: we should infer retention by selector in
+ // cases where we don't have an actual method.
+ } else {
+ Decl *D = 0;
+ if (ObjCMessageExpr *Send = dyn_cast<ObjCMessageExpr>(E)) {
+ D = Send->getMethodDecl();
+ } else {
+ CastExpr *CE = cast<CastExpr>(E);
+ // FIXME. What other cast kinds to check for?
+ if (CE->getCastKind() == CK_ObjCProduceObject ||
+ CE->getCastKind() == CK_LValueToRValue)
+ return MaybeBindToTemporary(CE->getSubExpr());
+ assert(CE->getCastKind() == CK_GetObjCProperty);
+ const ObjCPropertyRefExpr *PRE = CE->getSubExpr()->getObjCProperty();
+ D = (PRE->isImplicitProperty() ? PRE->getImplicitPropertyGetter() : 0);
+ }
- const RecordType *RT = E->getType()->getAs<RecordType>();
- if (!RT)
+ ReturnsRetained = (D && D->hasAttr<NSReturnsRetainedAttr>());
+ }
+
+ ExprNeedsCleanups = true;
+
+ CastKind ck = (ReturnsRetained ? CK_ObjCConsumeObject
+ : CK_ObjCReclaimReturnedObject);
+ return Owned(ImplicitCastExpr::Create(Context, E->getType(), ck, E, 0,
+ VK_RValue));
+ }
+
+ if (!getLangOptions().CPlusPlus)
return Owned(E);
- // If the result is a glvalue, we shouldn't bind it.
- if (E->Classify(Context).isGLValue())
+ const RecordType *RT = E->getType()->getAs<RecordType>();
+ if (!RT)
return Owned(E);
// That should be enough to guarantee that this type is complete.
@@ -3847,15 +4082,18 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) {
if (RD->isInvalidDecl() || RD->hasTrivialDestructor())
return Owned(E);
- CXXTemporary *Temp = CXXTemporary::Create(Context, LookupDestructor(RD));
- ExprTemporaries.push_back(Temp);
- if (CXXDestructorDecl *Destructor = LookupDestructor(RD)) {
+ CXXDestructorDecl *Destructor = LookupDestructor(RD);
+
+ CXXTemporary *Temp = CXXTemporary::Create(Context, Destructor);
+ if (Destructor) {
MarkDeclarationReferenced(E->getExprLoc(), Destructor);
CheckDestructorAccess(E->getExprLoc(), Destructor,
PDiag(diag::err_access_dtor_temp)
<< E->getType());
+
+ ExprTemporaries.push_back(Temp);
+ ExprNeedsCleanups = true;
}
- // FIXME: Add the temporary to the temporaries vector.
return Owned(CXXBindTemporaryExpr::Create(Context, Temp, E));
}
@@ -3864,14 +4102,16 @@ Expr *Sema::MaybeCreateExprWithCleanups(Expr *SubExpr) {
unsigned FirstTemporary = ExprEvalContexts.back().NumTemporaries;
assert(ExprTemporaries.size() >= FirstTemporary);
- if (ExprTemporaries.size() == FirstTemporary)
+ assert(ExprNeedsCleanups || ExprTemporaries.size() == FirstTemporary);
+ if (!ExprNeedsCleanups)
return SubExpr;
Expr *E = ExprWithCleanups::Create(Context, SubExpr,
- &ExprTemporaries[FirstTemporary],
+ ExprTemporaries.begin() + FirstTemporary,
ExprTemporaries.size() - FirstTemporary);
ExprTemporaries.erase(ExprTemporaries.begin() + FirstTemporary,
ExprTemporaries.end());
+ ExprNeedsCleanups = false;
return E;
}
@@ -3887,9 +4127,7 @@ Sema::MaybeCreateExprWithCleanups(ExprResult SubExpr) {
Stmt *Sema::MaybeCreateStmtWithCleanups(Stmt *SubStmt) {
assert(SubStmt && "sub statement can't be null!");
- unsigned FirstTemporary = ExprEvalContexts.back().NumTemporaries;
- assert(ExprTemporaries.size() >= FirstTemporary);
- if (ExprTemporaries.size() == FirstTemporary)
+ if (!ExprNeedsCleanups)
return SubStmt;
// FIXME: In order to attach the temporaries, wrap the statement into
@@ -4047,17 +4285,35 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base,
QualType DestructedType = DestructedTypeInfo->getType();
SourceLocation DestructedTypeStart
= DestructedTypeInfo->getTypeLoc().getLocalSourceRange().getBegin();
- if (!DestructedType->isDependentType() && !ObjectType->isDependentType() &&
- !Context.hasSameUnqualifiedType(DestructedType, ObjectType)) {
- Diag(DestructedTypeStart, diag::err_pseudo_dtor_type_mismatch)
- << ObjectType << DestructedType << Base->getSourceRange()
- << DestructedTypeInfo->getTypeLoc().getLocalSourceRange();
-
- // Recover by setting the destructed type to the object type.
- DestructedType = ObjectType;
- DestructedTypeInfo = Context.getTrivialTypeSourceInfo(ObjectType,
+ if (!DestructedType->isDependentType() && !ObjectType->isDependentType()) {
+ if (!Context.hasSameUnqualifiedType(DestructedType, ObjectType)) {
+ Diag(DestructedTypeStart, diag::err_pseudo_dtor_type_mismatch)
+ << ObjectType << DestructedType << Base->getSourceRange()
+ << DestructedTypeInfo->getTypeLoc().getLocalSourceRange();
+
+ // Recover by setting the destructed type to the object type.
+ DestructedType = ObjectType;
+ DestructedTypeInfo = Context.getTrivialTypeSourceInfo(ObjectType,
+ DestructedTypeStart);
+ Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo);
+ } else if (DestructedType.getObjCLifetime() !=
+ ObjectType.getObjCLifetime()) {
+
+ if (DestructedType.getObjCLifetime() == Qualifiers::OCL_None) {
+ // Okay: just pretend that the user provided the correctly-qualified
+ // type.
+ } else {
+ Diag(DestructedTypeStart, diag::err_arc_pseudo_dtor_inconstant_quals)
+ << ObjectType << DestructedType << Base->getSourceRange()
+ << DestructedTypeInfo->getTypeLoc().getLocalSourceRange();
+ }
+
+ // Recover by setting the destructed type to the object type.
+ DestructedType = ObjectType;
+ DestructedTypeInfo = Context.getTrivialTypeSourceInfo(ObjectType,
DestructedTypeStart);
- Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo);
+ Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo);
+ }
}
}
@@ -4293,7 +4549,16 @@ ExprResult Sema::IgnoredValueConversions(Expr *E) {
// [Except in specific positions,] an lvalue that does not have
// array type is converted to the value stored in the
// designated object (and is no longer an lvalue).
- if (E->isRValue()) return Owned(E);
+ if (E->isRValue()) {
+ // In C, function designators (i.e. expressions of function type)
+ // are r-values, but we still want to do function-to-pointer decay
+ // on them. This is both technically correct and convenient for
+ // some clients.
+ if (!getLangOptions().CPlusPlus && E->getType()->isFunctionType())
+ return DefaultFunctionArrayConversion(E);
+
+ return Owned(E);
+ }
// We always want to do this on ObjC property references.
if (E->getObjectKind() == OK_ObjCProperty) {
diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp
new file mode 100644
index 000000000000..2488dc8849dd
--- /dev/null
+++ b/lib/Sema/SemaExprMember.cpp
@@ -0,0 +1,1594 @@
+//===--- SemaExprMember.cpp - Semantic Analysis for Expressions -----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements semantic analysis member access expressions.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Sema/SemaInternal.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Scope.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/Lex/Preprocessor.h"
+
+using namespace clang;
+using namespace sema;
+
+/// Determines if the given class is provably not derived from all of
+/// the prospective base classes.
+static bool IsProvablyNotDerivedFrom(Sema &SemaRef,
+ CXXRecordDecl *Record,
+ const llvm::SmallPtrSet<CXXRecordDecl*, 4> &Bases) {
+ if (Bases.count(Record->getCanonicalDecl()))
+ return false;
+
+ RecordDecl *RD = Record->getDefinition();
+ if (!RD) return false;
+ Record = cast<CXXRecordDecl>(RD);
+
+ for (CXXRecordDecl::base_class_iterator I = Record->bases_begin(),
+ E = Record->bases_end(); I != E; ++I) {
+ CanQualType BaseT = SemaRef.Context.getCanonicalType((*I).getType());
+ CanQual<RecordType> BaseRT = BaseT->getAs<RecordType>();
+ if (!BaseRT) return false;
+
+ CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(BaseRT->getDecl());
+ if (!IsProvablyNotDerivedFrom(SemaRef, BaseRecord, Bases))
+ return false;
+ }
+
+ return true;
+}
+
+enum IMAKind {
+ /// The reference is definitely not an instance member access.
+ IMA_Static,
+
+ /// The reference may be an implicit instance member access.
+ IMA_Mixed,
+
+ /// The reference may be to an instance member, but it is invalid if
+ /// so, because the context is not an instance method.
+ IMA_Mixed_StaticContext,
+
+ /// The reference may be to an instance member, but it is invalid if
+ /// so, because the context is from an unrelated class.
+ IMA_Mixed_Unrelated,
+
+ /// The reference is definitely an implicit instance member access.
+ IMA_Instance,
+
+ /// The reference may be to an unresolved using declaration.
+ IMA_Unresolved,
+
+ /// The reference may be to an unresolved using declaration and the
+ /// context is not an instance method.
+ IMA_Unresolved_StaticContext,
+
+ /// All possible referrents are instance members and the current
+ /// context is not an instance method.
+ IMA_Error_StaticContext,
+
+ /// All possible referrents are instance members of an unrelated
+ /// class.
+ IMA_Error_Unrelated
+};
+
+/// The given lookup names class member(s) and is not being used for
+/// an address-of-member expression. Classify the type of access
+/// according to whether it's possible that this reference names an
+/// instance member. This is best-effort; it is okay to
+/// conservatively answer "yes", in which case some errors will simply
+/// not be caught until template-instantiation.
+static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
+ Scope *CurScope,
+ const LookupResult &R) {
+ assert(!R.empty() && (*R.begin())->isCXXClassMember());
+
+ DeclContext *DC = SemaRef.getFunctionLevelDeclContext();
+
+ bool isStaticContext =
+ (!isa<CXXMethodDecl>(DC) ||
+ cast<CXXMethodDecl>(DC)->isStatic());
+
+ // C++0x [expr.prim]p4:
+ // Otherwise, if a member-declarator declares a non-static data member
+ // of a class X, the expression this is a prvalue of type "pointer to X"
+ // within the optional brace-or-equal-initializer.
+ if (CurScope->getFlags() & Scope::ThisScope)
+ isStaticContext = false;
+
+ if (R.isUnresolvableResult())
+ return isStaticContext ? IMA_Unresolved_StaticContext : IMA_Unresolved;
+
+ // Collect all the declaring classes of instance members we find.
+ bool hasNonInstance = false;
+ bool hasField = false;
+ llvm::SmallPtrSet<CXXRecordDecl*, 4> Classes;
+ for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
+ NamedDecl *D = *I;
+
+ if (D->isCXXInstanceMember()) {
+ if (dyn_cast<FieldDecl>(D))
+ hasField = true;
+
+ CXXRecordDecl *R = cast<CXXRecordDecl>(D->getDeclContext());
+ Classes.insert(R->getCanonicalDecl());
+ }
+ else
+ hasNonInstance = true;
+ }
+
+ // If we didn't find any instance members, it can't be an implicit
+ // member reference.
+ if (Classes.empty())
+ return IMA_Static;
+
+ // If the current context is not an instance method, it can't be
+ // an implicit member reference.
+ if (isStaticContext) {
+ if (hasNonInstance)
+ return IMA_Mixed_StaticContext;
+
+ if (SemaRef.getLangOptions().CPlusPlus0x && hasField) {
+ // C++0x [expr.prim.general]p10:
+ // An id-expression that denotes a non-static data member or non-static
+ // member function of a class can only be used:
+ // (...)
+ // - if that id-expression denotes a non-static data member and it
+ // appears in an unevaluated operand.
+ const Sema::ExpressionEvaluationContextRecord& record
+ = SemaRef.ExprEvalContexts.back();
+ bool isUnevaluatedExpression = (record.Context == Sema::Unevaluated);
+ if (isUnevaluatedExpression)
+ return IMA_Mixed_StaticContext;
+ }
+
+ return IMA_Error_StaticContext;
+ }
+
+ CXXRecordDecl *contextClass;
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC))
+ contextClass = MD->getParent()->getCanonicalDecl();
+ else
+ contextClass = cast<CXXRecordDecl>(DC);
+
+ // [class.mfct.non-static]p3:
+ // ...is used in the body of a non-static member function of class X,
+ // if name lookup (3.4.1) resolves the name in the id-expression to a
+ // non-static non-type member of some class C [...]
+ // ...if C is not X or a base class of X, the class member access expression
+ // is ill-formed.
+ if (R.getNamingClass() &&
+ contextClass != R.getNamingClass()->getCanonicalDecl() &&
+ contextClass->isProvablyNotDerivedFrom(R.getNamingClass()))
+ return (hasNonInstance ? IMA_Mixed_Unrelated : IMA_Error_Unrelated);
+
+ // If we can prove that the current context is unrelated to all the
+ // declaring classes, it can't be an implicit member reference (in
+ // which case it's an error if any of those members are selected).
+ if (IsProvablyNotDerivedFrom(SemaRef, contextClass, Classes))
+ return (hasNonInstance ? IMA_Mixed_Unrelated : IMA_Error_Unrelated);
+
+ return (hasNonInstance ? IMA_Mixed : IMA_Instance);
+}
+
+/// Diagnose a reference to a field with no object available.
+static void DiagnoseInstanceReference(Sema &SemaRef,
+ const CXXScopeSpec &SS,
+ NamedDecl *rep,
+ const DeclarationNameInfo &nameInfo) {
+ SourceLocation Loc = nameInfo.getLoc();
+ SourceRange Range(Loc);
+ if (SS.isSet()) Range.setBegin(SS.getRange().getBegin());
+
+ if (isa<FieldDecl>(rep) || isa<IndirectFieldDecl>(rep)) {
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(SemaRef.CurContext)) {
+ if (MD->isStatic()) {
+ // "invalid use of member 'x' in static member function"
+ SemaRef.Diag(Loc, diag::err_invalid_member_use_in_static_method)
+ << Range << nameInfo.getName();
+ return;
+ }
+ }
+
+ SemaRef.Diag(Loc, diag::err_invalid_non_static_member_use)
+ << nameInfo.getName() << Range;
+ return;
+ }
+
+ SemaRef.Diag(Loc, diag::err_member_call_without_object) << Range;
+}
+
+/// Builds an expression which might be an implicit member expression.
+ExprResult
+Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS,
+ LookupResult &R,
+ const TemplateArgumentListInfo *TemplateArgs) {
+ switch (ClassifyImplicitMemberAccess(*this, CurScope, R)) {
+ case IMA_Instance:
+ return BuildImplicitMemberExpr(SS, R, TemplateArgs, true);
+
+ case IMA_Mixed:
+ case IMA_Mixed_Unrelated:
+ case IMA_Unresolved:
+ return BuildImplicitMemberExpr(SS, R, TemplateArgs, false);
+
+ case IMA_Static:
+ case IMA_Mixed_StaticContext:
+ case IMA_Unresolved_StaticContext:
+ if (TemplateArgs)
+ return BuildTemplateIdExpr(SS, R, false, *TemplateArgs);
+ return BuildDeclarationNameExpr(SS, R, false);
+
+ case IMA_Error_StaticContext:
+ case IMA_Error_Unrelated:
+ DiagnoseInstanceReference(*this, SS, R.getRepresentativeDecl(),
+ R.getLookupNameInfo());
+ return ExprError();
+ }
+
+ llvm_unreachable("unexpected instance member access kind");
+ return ExprError();
+}
+
+/// Check an ext-vector component access expression.
+///
+/// VK should be set in advance to the value kind of the base
+/// expression.
+static QualType
+CheckExtVectorComponent(Sema &S, QualType baseType, ExprValueKind &VK,
+ SourceLocation OpLoc, const IdentifierInfo *CompName,
+ SourceLocation CompLoc) {
+ // FIXME: Share logic with ExtVectorElementExpr::containsDuplicateElements,
+ // see FIXME there.
+ //
+ // FIXME: This logic can be greatly simplified by splitting it along
+ // halving/not halving and reworking the component checking.
+ const ExtVectorType *vecType = baseType->getAs<ExtVectorType>();
+
+ // The vector accessor can't exceed the number of elements.
+ const char *compStr = CompName->getNameStart();
+
+ // This flag determines whether or not the component is one of the four
+ // special names that indicate a subset of exactly half the elements are
+ // to be selected.
+ bool HalvingSwizzle = false;
+
+ // This flag determines whether or not CompName has an 's' char prefix,
+ // indicating that it is a string of hex values to be used as vector indices.
+ bool HexSwizzle = *compStr == 's' || *compStr == 'S';
+
+ bool HasRepeated = false;
+ bool HasIndex[16] = {};
+
+ int Idx;
+
+ // Check that we've found one of the special components, or that the component
+ // names must come from the same set.
+ if (!strcmp(compStr, "hi") || !strcmp(compStr, "lo") ||
+ !strcmp(compStr, "even") || !strcmp(compStr, "odd")) {
+ HalvingSwizzle = true;
+ } else if (!HexSwizzle &&
+ (Idx = vecType->getPointAccessorIdx(*compStr)) != -1) {
+ do {
+ if (HasIndex[Idx]) HasRepeated = true;
+ HasIndex[Idx] = true;
+ compStr++;
+ } while (*compStr && (Idx = vecType->getPointAccessorIdx(*compStr)) != -1);
+ } else {
+ if (HexSwizzle) compStr++;
+ while ((Idx = vecType->getNumericAccessorIdx(*compStr)) != -1) {
+ if (HasIndex[Idx]) HasRepeated = true;
+ HasIndex[Idx] = true;
+ compStr++;
+ }
+ }
+
+ if (!HalvingSwizzle && *compStr) {
+ // We didn't get to the end of the string. This means the component names
+ // didn't come from the same set *or* we encountered an illegal name.
+ S.Diag(OpLoc, diag::err_ext_vector_component_name_illegal)
+ << llvm::StringRef(compStr, 1) << SourceRange(CompLoc);
+ return QualType();
+ }
+
+ // Ensure no component accessor exceeds the width of the vector type it
+ // operates on.
+ if (!HalvingSwizzle) {
+ compStr = CompName->getNameStart();
+
+ if (HexSwizzle)
+ compStr++;
+
+ while (*compStr) {
+ if (!vecType->isAccessorWithinNumElements(*compStr++)) {
+ S.Diag(OpLoc, diag::err_ext_vector_component_exceeds_length)
+ << baseType << SourceRange(CompLoc);
+ return QualType();
+ }
+ }
+ }
+
+ // The component accessor looks fine - now we need to compute the actual type.
+ // The vector type is implied by the component accessor. For example,
+ // vec4.b is a float, vec4.xy is a vec2, vec4.rgb is a vec3, etc.
+ // vec4.s0 is a float, vec4.s23 is a vec3, etc.
+ // vec4.hi, vec4.lo, vec4.e, and vec4.o all return vec2.
+ unsigned CompSize = HalvingSwizzle ? (vecType->getNumElements() + 1) / 2
+ : CompName->getLength();
+ if (HexSwizzle)
+ CompSize--;
+
+ if (CompSize == 1)
+ return vecType->getElementType();
+
+ if (HasRepeated) VK = VK_RValue;
+
+ QualType VT = S.Context.getExtVectorType(vecType->getElementType(), CompSize);
+ // Now look up the TypeDefDecl from the vector type. Without this,
+ // diagostics look bad. We want extended vector types to appear built-in.
+ for (unsigned i = 0, E = S.ExtVectorDecls.size(); i != E; ++i) {
+ if (S.ExtVectorDecls[i]->getUnderlyingType() == VT)
+ return S.Context.getTypedefType(S.ExtVectorDecls[i]);
+ }
+ return VT; // should never get here (a typedef type should always be found).
+}
+
+static Decl *FindGetterSetterNameDeclFromProtocolList(const ObjCProtocolDecl*PDecl,
+ IdentifierInfo *Member,
+ const Selector &Sel,
+ ASTContext &Context) {
+ if (Member)
+ if (ObjCPropertyDecl *PD = PDecl->FindPropertyDeclaration(Member))
+ return PD;
+ if (ObjCMethodDecl *OMD = PDecl->getInstanceMethod(Sel))
+ return OMD;
+
+ for (ObjCProtocolDecl::protocol_iterator I = PDecl->protocol_begin(),
+ E = PDecl->protocol_end(); I != E; ++I) {
+ if (Decl *D = FindGetterSetterNameDeclFromProtocolList(*I, Member, Sel,
+ Context))
+ return D;
+ }
+ return 0;
+}
+
+static Decl *FindGetterSetterNameDecl(const ObjCObjectPointerType *QIdTy,
+ IdentifierInfo *Member,
+ const Selector &Sel,
+ ASTContext &Context) {
+ // Check protocols on qualified interfaces.
+ Decl *GDecl = 0;
+ for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(),
+ E = QIdTy->qual_end(); I != E; ++I) {
+ if (Member)
+ if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Member)) {
+ GDecl = PD;
+ break;
+ }
+ // Also must look for a getter or setter name which uses property syntax.
+ if (ObjCMethodDecl *OMD = (*I)->getInstanceMethod(Sel)) {
+ GDecl = OMD;
+ break;
+ }
+ }
+ if (!GDecl) {
+ for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(),
+ E = QIdTy->qual_end(); I != E; ++I) {
+ // Search in the protocol-qualifier list of current protocol.
+ GDecl = FindGetterSetterNameDeclFromProtocolList(*I, Member, Sel,
+ Context);
+ if (GDecl)
+ return GDecl;
+ }
+ }
+ return GDecl;
+}
+
+ExprResult
+Sema::ActOnDependentMemberExpr(Expr *BaseExpr, QualType BaseType,
+ bool IsArrow, SourceLocation OpLoc,
+ const CXXScopeSpec &SS,
+ NamedDecl *FirstQualifierInScope,
+ const DeclarationNameInfo &NameInfo,
+ const TemplateArgumentListInfo *TemplateArgs) {
+ // Even in dependent contexts, try to diagnose base expressions with
+ // obviously wrong types, e.g.:
+ //
+ // T* t;
+ // t.f;
+ //
+ // In Obj-C++, however, the above expression is valid, since it could be
+ // accessing the 'f' property if T is an Obj-C interface. The extra check
+ // allows this, while still reporting an error if T is a struct pointer.
+ if (!IsArrow) {
+ const PointerType *PT = BaseType->getAs<PointerType>();
+ if (PT && (!getLangOptions().ObjC1 ||
+ PT->getPointeeType()->isRecordType())) {
+ assert(BaseExpr && "cannot happen with implicit member accesses");
+ Diag(NameInfo.getLoc(), diag::err_typecheck_member_reference_struct_union)
+ << BaseType << BaseExpr->getSourceRange();
+ return ExprError();
+ }
+ }
+
+ assert(BaseType->isDependentType() ||
+ NameInfo.getName().isDependentName() ||
+ isDependentScopeSpecifier(SS));
+
+ // Get the type being accessed in BaseType. If this is an arrow, the BaseExpr
+ // must have pointer type, and the accessed type is the pointee.
+ return Owned(CXXDependentScopeMemberExpr::Create(Context, BaseExpr, BaseType,
+ IsArrow, OpLoc,
+ SS.getWithLocInContext(Context),
+ FirstQualifierInScope,
+ NameInfo, TemplateArgs));
+}
+
+/// We know that the given qualified member reference points only to
+/// declarations which do not belong to the static type of the base
+/// expression. Diagnose the problem.
+static void DiagnoseQualifiedMemberReference(Sema &SemaRef,
+ Expr *BaseExpr,
+ QualType BaseType,
+ const CXXScopeSpec &SS,
+ NamedDecl *rep,
+ const DeclarationNameInfo &nameInfo) {
+ // If this is an implicit member access, use a different set of
+ // diagnostics.
+ if (!BaseExpr)
+ return DiagnoseInstanceReference(SemaRef, SS, rep, nameInfo);
+
+ SemaRef.Diag(nameInfo.getLoc(), diag::err_qualified_member_of_unrelated)
+ << SS.getRange() << rep << BaseType;
+}
+
+// Check whether the declarations we found through a nested-name
+// specifier in a member expression are actually members of the base
+// type. The restriction here is:
+//
+// C++ [expr.ref]p2:
+// ... In these cases, the id-expression shall name a
+// member of the class or of one of its base classes.
+//
+// So it's perfectly legitimate for the nested-name specifier to name
+// an unrelated class, and for us to find an overload set including
+// decls from classes which are not superclasses, as long as the decl
+// we actually pick through overload resolution is from a superclass.
+bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr,
+ QualType BaseType,
+ const CXXScopeSpec &SS,
+ const LookupResult &R) {
+ const RecordType *BaseRT = BaseType->getAs<RecordType>();
+ if (!BaseRT) {
+ // We can't check this yet because the base type is still
+ // dependent.
+ assert(BaseType->isDependentType());
+ return false;
+ }
+ CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(BaseRT->getDecl());
+
+ for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
+ // If this is an implicit member reference and we find a
+ // non-instance member, it's not an error.
+ if (!BaseExpr && !(*I)->isCXXInstanceMember())
+ return false;
+
+ // Note that we use the DC of the decl, not the underlying decl.
+ DeclContext *DC = (*I)->getDeclContext();
+ while (DC->isTransparentContext())
+ DC = DC->getParent();
+
+ if (!DC->isRecord())
+ continue;
+
+ llvm::SmallPtrSet<CXXRecordDecl*,4> MemberRecord;
+ MemberRecord.insert(cast<CXXRecordDecl>(DC)->getCanonicalDecl());
+
+ if (!IsProvablyNotDerivedFrom(*this, BaseRecord, MemberRecord))
+ return false;
+ }
+
+ DiagnoseQualifiedMemberReference(*this, BaseExpr, BaseType, SS,
+ R.getRepresentativeDecl(),
+ R.getLookupNameInfo());
+ return true;
+}
+
+static bool
+LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
+ SourceRange BaseRange, const RecordType *RTy,
+ SourceLocation OpLoc, CXXScopeSpec &SS,
+ bool HasTemplateArgs) {
+ RecordDecl *RDecl = RTy->getDecl();
+ if (SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0),
+ SemaRef.PDiag(diag::err_typecheck_incomplete_tag)
+ << BaseRange))
+ return true;
+
+ if (HasTemplateArgs) {
+ // LookupTemplateName doesn't expect these both to exist simultaneously.
+ QualType ObjectType = SS.isSet() ? QualType() : QualType(RTy, 0);
+
+ bool MOUS;
+ SemaRef.LookupTemplateName(R, 0, SS, ObjectType, false, MOUS);
+ return false;
+ }
+
+ DeclContext *DC = RDecl;
+ if (SS.isSet()) {
+ // If the member name was a qualified-id, look into the
+ // nested-name-specifier.
+ DC = SemaRef.computeDeclContext(SS, false);
+
+ if (SemaRef.RequireCompleteDeclContext(SS, DC)) {
+ SemaRef.Diag(SS.getRange().getEnd(), diag::err_typecheck_incomplete_tag)
+ << SS.getRange() << DC;
+ return true;
+ }
+
+ assert(DC && "Cannot handle non-computable dependent contexts in lookup");
+
+ if (!isa<TypeDecl>(DC)) {
+ SemaRef.Diag(R.getNameLoc(), diag::err_qualified_member_nonclass)
+ << DC << SS.getRange();
+ return true;
+ }
+ }
+
+ // The record definition is complete, now look up the member.
+ SemaRef.LookupQualifiedName(R, DC);
+
+ if (!R.empty())
+ return false;
+
+ // We didn't find anything with the given name, so try to correct
+ // for typos.
+ DeclarationName Name = R.getLookupName();
+ TypoCorrection Corrected = SemaRef.CorrectTypo(R.getLookupNameInfo(),
+ R.getLookupKind(), NULL,
+ &SS, DC, false,
+ Sema::CTC_MemberLookup);
+ NamedDecl *ND = Corrected.getCorrectionDecl();
+ R.clear();
+ if (ND && (isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND))) {
+ std::string CorrectedStr(
+ Corrected.getAsString(SemaRef.getLangOptions()));
+ std::string CorrectedQuotedStr(
+ Corrected.getQuoted(SemaRef.getLangOptions()));
+ R.setLookupName(Corrected.getCorrection());
+ R.addDecl(ND);
+ SemaRef.Diag(R.getNameLoc(), diag::err_no_member_suggest)
+ << Name << DC << CorrectedQuotedStr << SS.getRange()
+ << FixItHint::CreateReplacement(R.getNameLoc(), CorrectedStr);
+ SemaRef.Diag(ND->getLocation(), diag::note_previous_decl)
+ << ND->getDeclName();
+ }
+
+ return false;
+}
+
+ExprResult
+Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
+ SourceLocation OpLoc, bool IsArrow,
+ CXXScopeSpec &SS,
+ NamedDecl *FirstQualifierInScope,
+ const DeclarationNameInfo &NameInfo,
+ const TemplateArgumentListInfo *TemplateArgs) {
+ if (BaseType->isDependentType() ||
+ (SS.isSet() && isDependentScopeSpecifier(SS)))
+ return ActOnDependentMemberExpr(Base, BaseType,
+ IsArrow, OpLoc,
+ SS, FirstQualifierInScope,
+ NameInfo, TemplateArgs);
+
+ LookupResult R(*this, NameInfo, LookupMemberName);
+
+ // Implicit member accesses.
+ if (!Base) {
+ QualType RecordTy = BaseType;
+ if (IsArrow) RecordTy = RecordTy->getAs<PointerType>()->getPointeeType();
+ if (LookupMemberExprInRecord(*this, R, SourceRange(),
+ RecordTy->getAs<RecordType>(),
+ OpLoc, SS, TemplateArgs != 0))
+ return ExprError();
+
+ // Explicit member accesses.
+ } else {
+ ExprResult BaseResult = Owned(Base);
+ ExprResult Result =
+ LookupMemberExpr(R, BaseResult, IsArrow, OpLoc,
+ SS, /*ObjCImpDecl*/ 0, TemplateArgs != 0);
+
+ if (BaseResult.isInvalid())
+ return ExprError();
+ Base = BaseResult.take();
+
+ if (Result.isInvalid()) {
+ Owned(Base);
+ return ExprError();
+ }
+
+ if (Result.get())
+ return move(Result);
+
+ // LookupMemberExpr can modify Base, and thus change BaseType
+ BaseType = Base->getType();
+ }
+
+ return BuildMemberReferenceExpr(Base, BaseType,
+ OpLoc, IsArrow, SS, FirstQualifierInScope,
+ R, TemplateArgs);
+}
+
+static ExprResult
+BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow,
+ const CXXScopeSpec &SS, FieldDecl *Field,
+ DeclAccessPair FoundDecl,
+ const DeclarationNameInfo &MemberNameInfo);
+
+ExprResult
+Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
+ SourceLocation loc,
+ IndirectFieldDecl *indirectField,
+ Expr *baseObjectExpr,
+ SourceLocation opLoc) {
+ // First, build the expression that refers to the base object.
+
+ bool baseObjectIsPointer = false;
+ Qualifiers baseQuals;
+
+ // Case 1: the base of the indirect field is not a field.
+ VarDecl *baseVariable = indirectField->getVarDecl();
+ CXXScopeSpec EmptySS;
+ if (baseVariable) {
+ assert(baseVariable->getType()->isRecordType());
+
+ // In principle we could have a member access expression that
+ // accesses an anonymous struct/union that's a static member of
+ // the base object's class. However, under the current standard,
+ // static data members cannot be anonymous structs or unions.
+ // Supporting this is as easy as building a MemberExpr here.
+ assert(!baseObjectExpr && "anonymous struct/union is static data member?");
+
+ DeclarationNameInfo baseNameInfo(DeclarationName(), loc);
+
+ ExprResult result
+ = BuildDeclarationNameExpr(EmptySS, baseNameInfo, baseVariable);
+ if (result.isInvalid()) return ExprError();
+
+ baseObjectExpr = result.take();
+ baseObjectIsPointer = false;
+ baseQuals = baseObjectExpr->getType().getQualifiers();
+
+ // Case 2: the base of the indirect field is a field and the user
+ // wrote a member expression.
+ } else if (baseObjectExpr) {
+ // The caller provided the base object expression. Determine
+ // whether its a pointer and whether it adds any qualifiers to the
+ // anonymous struct/union fields we're looking into.
+ QualType objectType = baseObjectExpr->getType();
+
+ if (const PointerType *ptr = objectType->getAs<PointerType>()) {
+ baseObjectIsPointer = true;
+ objectType = ptr->getPointeeType();
+ } else {
+ baseObjectIsPointer = false;
+ }
+ baseQuals = objectType.getQualifiers();
+
+ // Case 3: the base of the indirect field is a field and we should
+ // build an implicit member access.
+ } else {
+ // We've found a member of an anonymous struct/union that is
+ // inside a non-anonymous struct/union, so in a well-formed
+ // program our base object expression is "this".
+ QualType ThisTy = getAndCaptureCurrentThisType();
+ if (ThisTy.isNull()) {
+ Diag(loc, diag::err_invalid_member_use_in_static_method)
+ << indirectField->getDeclName();
+ return ExprError();
+ }
+
+ // Our base object expression is "this".
+ baseObjectExpr
+ = new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/ true);
+ baseObjectIsPointer = true;
+ baseQuals = ThisTy->castAs<PointerType>()->getPointeeType().getQualifiers();
+ }
+
+ // Build the implicit member references to the field of the
+ // anonymous struct/union.
+ Expr *result = baseObjectExpr;
+ IndirectFieldDecl::chain_iterator
+ FI = indirectField->chain_begin(), FEnd = indirectField->chain_end();
+
+ // Build the first member access in the chain with full information.
+ if (!baseVariable) {
+ FieldDecl *field = cast<FieldDecl>(*FI);
+
+ // FIXME: use the real found-decl info!
+ DeclAccessPair foundDecl = DeclAccessPair::make(field, field->getAccess());
+
+ // Make a nameInfo that properly uses the anonymous name.
+ DeclarationNameInfo memberNameInfo(field->getDeclName(), loc);
+
+ result = BuildFieldReferenceExpr(*this, result, baseObjectIsPointer,
+ EmptySS, field, foundDecl,
+ memberNameInfo).take();
+ baseObjectIsPointer = false;
+
+ // FIXME: check qualified member access
+ }
+
+ // In all cases, we should now skip the first declaration in the chain.
+ ++FI;
+
+ while (FI != FEnd) {
+ FieldDecl *field = cast<FieldDecl>(*FI++);
+
+ // FIXME: these are somewhat meaningless
+ DeclarationNameInfo memberNameInfo(field->getDeclName(), loc);
+ DeclAccessPair foundDecl = DeclAccessPair::make(field, field->getAccess());
+
+ result = BuildFieldReferenceExpr(*this, result, /*isarrow*/ false,
+ (FI == FEnd? SS : EmptySS), field,
+ foundDecl, memberNameInfo).take();
+ }
+
+ return Owned(result);
+}
+
+/// \brief Build a MemberExpr AST node.
+static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow,
+ const CXXScopeSpec &SS, ValueDecl *Member,
+ DeclAccessPair FoundDecl,
+ const DeclarationNameInfo &MemberNameInfo,
+ QualType Ty,
+ ExprValueKind VK, ExprObjectKind OK,
+ const TemplateArgumentListInfo *TemplateArgs = 0) {
+ return MemberExpr::Create(C, Base, isArrow, SS.getWithLocInContext(C),
+ Member, FoundDecl, MemberNameInfo,
+ TemplateArgs, Ty, VK, OK);
+}
+
+ExprResult
+Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
+ SourceLocation OpLoc, bool IsArrow,
+ const CXXScopeSpec &SS,
+ NamedDecl *FirstQualifierInScope,
+ LookupResult &R,
+ const TemplateArgumentListInfo *TemplateArgs,
+ bool SuppressQualifierCheck) {
+ QualType BaseType = BaseExprType;
+ if (IsArrow) {
+ assert(BaseType->isPointerType());
+ BaseType = BaseType->getAs<PointerType>()->getPointeeType();
+ }
+ R.setBaseObjectType(BaseType);
+
+ const DeclarationNameInfo &MemberNameInfo = R.getLookupNameInfo();
+ DeclarationName MemberName = MemberNameInfo.getName();
+ SourceLocation MemberLoc = MemberNameInfo.getLoc();
+
+ if (R.isAmbiguous())
+ return ExprError();
+
+ if (R.empty()) {
+ // Rederive where we looked up.
+ DeclContext *DC = (SS.isSet()
+ ? computeDeclContext(SS, false)
+ : BaseType->getAs<RecordType>()->getDecl());
+
+ Diag(R.getNameLoc(), diag::err_no_member)
+ << MemberName << DC
+ << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange());
+ return ExprError();
+ }
+
+ // Diagnose lookups that find only declarations from a non-base
+ // type. This is possible for either qualified lookups (which may
+ // have been qualified with an unrelated type) or implicit member
+ // expressions (which were found with unqualified lookup and thus
+ // may have come from an enclosing scope). Note that it's okay for
+ // lookup to find declarations from a non-base type as long as those
+ // aren't the ones picked by overload resolution.
+ if ((SS.isSet() || !BaseExpr ||
+ (isa<CXXThisExpr>(BaseExpr) &&
+ cast<CXXThisExpr>(BaseExpr)->isImplicit())) &&
+ !SuppressQualifierCheck &&
+ CheckQualifiedMemberReference(BaseExpr, BaseType, SS, R))
+ return ExprError();
+
+ // Construct an unresolved result if we in fact got an unresolved
+ // result.
+ if (R.isOverloadedResult() || R.isUnresolvableResult()) {
+ // Suppress any lookup-related diagnostics; we'll do these when we
+ // pick a member.
+ R.suppressDiagnostics();
+
+ UnresolvedMemberExpr *MemExpr
+ = UnresolvedMemberExpr::Create(Context, R.isUnresolvableResult(),
+ BaseExpr, BaseExprType,
+ IsArrow, OpLoc,
+ SS.getWithLocInContext(Context),
+ MemberNameInfo,
+ TemplateArgs, R.begin(), R.end());
+
+ return Owned(MemExpr);
+ }
+
+ assert(R.isSingleResult());
+ DeclAccessPair FoundDecl = R.begin().getPair();
+ NamedDecl *MemberDecl = R.getFoundDecl();
+
+ // FIXME: diagnose the presence of template arguments now.
+
+ // If the decl being referenced had an error, return an error for this
+ // sub-expr without emitting another error, in order to avoid cascading
+ // error cases.
+ if (MemberDecl->isInvalidDecl())
+ return ExprError();
+
+ // Handle the implicit-member-access case.
+ if (!BaseExpr) {
+ // If this is not an instance member, convert to a non-member access.
+ if (!MemberDecl->isCXXInstanceMember())
+ return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(), MemberDecl);
+
+ SourceLocation Loc = R.getNameLoc();
+ if (SS.getRange().isValid())
+ Loc = SS.getRange().getBegin();
+ BaseExpr = new (Context) CXXThisExpr(Loc, BaseExprType,/*isImplicit=*/true);
+ }
+
+ bool ShouldCheckUse = true;
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MemberDecl)) {
+ // Don't diagnose the use of a virtual member function unless it's
+ // explicitly qualified.
+ if (MD->isVirtual() && !SS.isSet())
+ ShouldCheckUse = false;
+ }
+
+ // Check the use of this member.
+ if (ShouldCheckUse && DiagnoseUseOfDecl(MemberDecl, MemberLoc)) {
+ Owned(BaseExpr);
+ return ExprError();
+ }
+
+ // Perform a property load on the base regardless of whether we
+ // actually need it for the declaration.
+ if (BaseExpr->getObjectKind() == OK_ObjCProperty) {
+ ExprResult Result = ConvertPropertyForRValue(BaseExpr);
+ if (Result.isInvalid())
+ return ExprError();
+ BaseExpr = Result.take();
+ }
+
+ if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl))
+ return BuildFieldReferenceExpr(*this, BaseExpr, IsArrow,
+ SS, FD, FoundDecl, MemberNameInfo);
+
+ if (IndirectFieldDecl *FD = dyn_cast<IndirectFieldDecl>(MemberDecl))
+ // We may have found a field within an anonymous union or struct
+ // (C++ [class.union]).
+ return BuildAnonymousStructUnionMemberReference(SS, MemberLoc, FD,
+ BaseExpr, OpLoc);
+
+ if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) {
+ MarkDeclarationReferenced(MemberLoc, Var);
+ return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS,
+ Var, FoundDecl, MemberNameInfo,
+ Var->getType().getNonReferenceType(),
+ VK_LValue, OK_Ordinary));
+ }
+
+ if (CXXMethodDecl *MemberFn = dyn_cast<CXXMethodDecl>(MemberDecl)) {
+ ExprValueKind valueKind;
+ QualType type;
+ if (MemberFn->isInstance()) {
+ valueKind = VK_RValue;
+ type = Context.BoundMemberTy;
+ } else {
+ valueKind = VK_LValue;
+ type = MemberFn->getType();
+ }
+
+ MarkDeclarationReferenced(MemberLoc, MemberDecl);
+ return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS,
+ MemberFn, FoundDecl, MemberNameInfo,
+ type, valueKind, OK_Ordinary));
+ }
+ assert(!isa<FunctionDecl>(MemberDecl) && "member function not C++ method?");
+
+ if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) {
+ MarkDeclarationReferenced(MemberLoc, MemberDecl);
+ return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS,
+ Enum, FoundDecl, MemberNameInfo,
+ Enum->getType(), VK_RValue, OK_Ordinary));
+ }
+
+ Owned(BaseExpr);
+
+ // We found something that we didn't expect. Complain.
+ if (isa<TypeDecl>(MemberDecl))
+ Diag(MemberLoc, diag::err_typecheck_member_reference_type)
+ << MemberName << BaseType << int(IsArrow);
+ else
+ Diag(MemberLoc, diag::err_typecheck_member_reference_unknown)
+ << MemberName << BaseType << int(IsArrow);
+
+ Diag(MemberDecl->getLocation(), diag::note_member_declared_here)
+ << MemberName;
+ R.suppressDiagnostics();
+ return ExprError();
+}
+
+/// Given that normal member access failed on the given expression,
+/// and given that the expression's type involves builtin-id or
+/// builtin-Class, decide whether substituting in the redefinition
+/// types would be profitable. The redefinition type is whatever
+/// this translation unit tried to typedef to id/Class; we store
+/// it to the side and then re-use it in places like this.
+static bool ShouldTryAgainWithRedefinitionType(Sema &S, ExprResult &base) {
+ const ObjCObjectPointerType *opty
+ = base.get()->getType()->getAs<ObjCObjectPointerType>();
+ if (!opty) return false;
+
+ const ObjCObjectType *ty = opty->getObjectType();
+
+ QualType redef;
+ if (ty->isObjCId()) {
+ redef = S.Context.ObjCIdRedefinitionType;
+ } else if (ty->isObjCClass()) {
+ redef = S.Context.ObjCClassRedefinitionType;
+ } else {
+ return false;
+ }
+
+ // Do the substitution as long as the redefinition type isn't just a
+ // possibly-qualified pointer to builtin-id or builtin-Class again.
+ opty = redef->getAs<ObjCObjectPointerType>();
+ if (opty && !opty->getObjectType()->getInterface() != 0)
+ return false;
+
+ base = S.ImpCastExprToType(base.take(), redef, CK_BitCast);
+ return true;
+}
+
+/// Look up the given member of the given non-type-dependent
+/// expression. This can return in one of two ways:
+/// * If it returns a sentinel null-but-valid result, the caller will
+/// assume that lookup was performed and the results written into
+/// the provided structure. It will take over from there.
+/// * Otherwise, the returned expression will be produced in place of
+/// an ordinary member expression.
+///
+/// The ObjCImpDecl bit is a gross hack that will need to be properly
+/// fixed for ObjC++.
+ExprResult
+Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
+ bool &IsArrow, SourceLocation OpLoc,
+ CXXScopeSpec &SS,
+ Decl *ObjCImpDecl, bool HasTemplateArgs) {
+ assert(BaseExpr.get() && "no base expression");
+
+ // Perform default conversions.
+ BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take());
+
+ if (IsArrow) {
+ BaseExpr = DefaultLvalueConversion(BaseExpr.take());
+ if (BaseExpr.isInvalid())
+ return ExprError();
+ }
+
+ QualType BaseType = BaseExpr.get()->getType();
+ assert(!BaseType->isDependentType());
+
+ DeclarationName MemberName = R.getLookupName();
+ SourceLocation MemberLoc = R.getNameLoc();
+
+ // For later type-checking purposes, turn arrow accesses into dot
+ // accesses. The only access type we support that doesn't follow
+ // the C equivalence "a->b === (*a).b" is ObjC property accesses,
+ // and those never use arrows, so this is unaffected.
+ if (IsArrow) {
+ if (const PointerType *Ptr = BaseType->getAs<PointerType>())
+ BaseType = Ptr->getPointeeType();
+ else if (const ObjCObjectPointerType *Ptr
+ = BaseType->getAs<ObjCObjectPointerType>())
+ BaseType = Ptr->getPointeeType();
+ else if (BaseType->isRecordType()) {
+ // Recover from arrow accesses to records, e.g.:
+ // struct MyRecord foo;
+ // foo->bar
+ // This is actually well-formed in C++ if MyRecord has an
+ // overloaded operator->, but that should have been dealt with
+ // by now.
+ Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
+ << BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange()
+ << FixItHint::CreateReplacement(OpLoc, ".");
+ IsArrow = false;
+ } else if (BaseType == Context.BoundMemberTy) {
+ goto fail;
+ } else {
+ Diag(MemberLoc, diag::err_typecheck_member_reference_arrow)
+ << BaseType << BaseExpr.get()->getSourceRange();
+ return ExprError();
+ }
+ }
+
+ // Handle field access to simple records.
+ if (const RecordType *RTy = BaseType->getAs<RecordType>()) {
+ if (LookupMemberExprInRecord(*this, R, BaseExpr.get()->getSourceRange(),
+ RTy, OpLoc, SS, HasTemplateArgs))
+ return ExprError();
+
+ // Returning valid-but-null is how we indicate to the caller that
+ // the lookup result was filled in.
+ return Owned((Expr*) 0);
+ }
+
+ // Handle ivar access to Objective-C objects.
+ if (const ObjCObjectType *OTy = BaseType->getAs<ObjCObjectType>()) {
+ IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
+
+ // There are three cases for the base type:
+ // - builtin id (qualified or unqualified)
+ // - builtin Class (qualified or unqualified)
+ // - an interface
+ ObjCInterfaceDecl *IDecl = OTy->getInterface();
+ if (!IDecl) {
+ if (getLangOptions().ObjCAutoRefCount &&
+ (OTy->isObjCId() || OTy->isObjCClass()))
+ goto fail;
+ // There's an implicit 'isa' ivar on all objects.
+ // But we only actually find it this way on objects of type 'id',
+ // apparently.
+ if (OTy->isObjCId() && Member->isStr("isa"))
+ return Owned(new (Context) ObjCIsaExpr(BaseExpr.take(), IsArrow, MemberLoc,
+ Context.getObjCClassType()));
+
+ if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr))
+ return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
+ ObjCImpDecl, HasTemplateArgs);
+ goto fail;
+ }
+
+ ObjCInterfaceDecl *ClassDeclared;
+ ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(Member, ClassDeclared);
+
+ if (!IV) {
+ // Attempt to correct for typos in ivar names.
+ LookupResult Res(*this, R.getLookupName(), R.getNameLoc(),
+ LookupMemberName);
+ TypoCorrection Corrected = CorrectTypo(
+ R.getLookupNameInfo(), LookupMemberName, NULL, NULL, IDecl, false,
+ IsArrow ? CTC_ObjCIvarLookup : CTC_ObjCPropertyLookup);
+ if ((IV = Corrected.getCorrectionDeclAs<ObjCIvarDecl>())) {
+ Diag(R.getNameLoc(),
+ diag::err_typecheck_member_reference_ivar_suggest)
+ << IDecl->getDeclName() << MemberName << IV->getDeclName()
+ << FixItHint::CreateReplacement(R.getNameLoc(),
+ IV->getNameAsString());
+ Diag(IV->getLocation(), diag::note_previous_decl)
+ << IV->getDeclName();
+ } else {
+ if (IsArrow && IDecl->FindPropertyDeclaration(Member)) {
+ Diag(MemberLoc,
+ diag::err_property_found_suggest)
+ << Member << BaseExpr.get()->getType()
+ << FixItHint::CreateReplacement(OpLoc, ".");
+ return ExprError();
+ }
+ Res.clear();
+ Res.setLookupName(Member);
+
+ Diag(MemberLoc, diag::err_typecheck_member_reference_ivar)
+ << IDecl->getDeclName() << MemberName
+ << BaseExpr.get()->getSourceRange();
+ return ExprError();
+ }
+ }
+
+ // If the decl being referenced had an error, return an error for this
+ // sub-expr without emitting another error, in order to avoid cascading
+ // error cases.
+ if (IV->isInvalidDecl())
+ return ExprError();
+
+ // Check whether we can reference this field.
+ if (DiagnoseUseOfDecl(IV, MemberLoc))
+ return ExprError();
+ if (IV->getAccessControl() != ObjCIvarDecl::Public &&
+ IV->getAccessControl() != ObjCIvarDecl::Package) {
+ ObjCInterfaceDecl *ClassOfMethodDecl = 0;
+ if (ObjCMethodDecl *MD = getCurMethodDecl())
+ ClassOfMethodDecl = MD->getClassInterface();
+ else if (ObjCImpDecl && getCurFunctionDecl()) {
+ // Case of a c-function declared inside an objc implementation.
+ // FIXME: For a c-style function nested inside an objc implementation
+ // class, there is no implementation context available, so we pass
+ // down the context as argument to this routine. Ideally, this context
+ // need be passed down in the AST node and somehow calculated from the
+ // AST for a function decl.
+ if (ObjCImplementationDecl *IMPD =
+ dyn_cast<ObjCImplementationDecl>(ObjCImpDecl))
+ ClassOfMethodDecl = IMPD->getClassInterface();
+ else if (ObjCCategoryImplDecl* CatImplClass =
+ dyn_cast<ObjCCategoryImplDecl>(ObjCImpDecl))
+ ClassOfMethodDecl = CatImplClass->getClassInterface();
+ }
+
+ if (IV->getAccessControl() == ObjCIvarDecl::Private) {
+ if (ClassDeclared != IDecl ||
+ ClassOfMethodDecl != ClassDeclared)
+ Diag(MemberLoc, diag::error_private_ivar_access)
+ << IV->getDeclName();
+ } else if (!IDecl->isSuperClassOf(ClassOfMethodDecl))
+ // @protected
+ Diag(MemberLoc, diag::error_protected_ivar_access)
+ << IV->getDeclName();
+ }
+ if (getLangOptions().ObjCAutoRefCount) {
+ Expr *BaseExp = BaseExpr.get()->IgnoreParenImpCasts();
+ if (UnaryOperator *UO = dyn_cast<UnaryOperator>(BaseExp))
+ if (UO->getOpcode() == UO_Deref)
+ BaseExp = UO->getSubExpr()->IgnoreParenCasts();
+
+ if (DeclRefExpr *DE = dyn_cast<DeclRefExpr>(BaseExp))
+ if (DE->getType().getObjCLifetime() == Qualifiers::OCL_Weak)
+ Diag(DE->getLocation(), diag::error_arc_weak_ivar_access);
+ }
+
+ return Owned(new (Context) ObjCIvarRefExpr(IV, IV->getType(),
+ MemberLoc, BaseExpr.take(),
+ IsArrow));
+ }
+
+ // Objective-C property access.
+ const ObjCObjectPointerType *OPT;
+ if (!IsArrow && (OPT = BaseType->getAs<ObjCObjectPointerType>())) {
+ // This actually uses the base as an r-value.
+ BaseExpr = DefaultLvalueConversion(BaseExpr.take());
+ if (BaseExpr.isInvalid())
+ return ExprError();
+
+ assert(Context.hasSameUnqualifiedType(BaseType, BaseExpr.get()->getType()));
+
+ IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
+
+ const ObjCObjectType *OT = OPT->getObjectType();
+
+ // id, with and without qualifiers.
+ if (OT->isObjCId()) {
+ // Check protocols on qualified interfaces.
+ Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
+ if (Decl *PMDecl = FindGetterSetterNameDecl(OPT, Member, Sel, Context)) {
+ if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(PMDecl)) {
+ // Check the use of this declaration
+ if (DiagnoseUseOfDecl(PD, MemberLoc))
+ return ExprError();
+
+ QualType T = PD->getType();
+ if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl())
+ T = getMessageSendResultType(BaseType, Getter, false, false);
+
+ return Owned(new (Context) ObjCPropertyRefExpr(PD, T,
+ VK_LValue,
+ OK_ObjCProperty,
+ MemberLoc,
+ BaseExpr.take()));
+ }
+
+ if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(PMDecl)) {
+ // Check the use of this method.
+ if (DiagnoseUseOfDecl(OMD, MemberLoc))
+ return ExprError();
+ Selector SetterSel =
+ SelectorTable::constructSetterName(PP.getIdentifierTable(),
+ PP.getSelectorTable(), Member);
+ ObjCMethodDecl *SMD = 0;
+ if (Decl *SDecl = FindGetterSetterNameDecl(OPT, /*Property id*/0,
+ SetterSel, Context))
+ SMD = dyn_cast<ObjCMethodDecl>(SDecl);
+ QualType PType = getMessageSendResultType(BaseType, OMD, false,
+ false);
+
+ ExprValueKind VK = VK_LValue;
+ if (!getLangOptions().CPlusPlus && PType.isCForbiddenLValueType())
+ VK = VK_RValue;
+ ExprObjectKind OK = (VK == VK_RValue ? OK_Ordinary : OK_ObjCProperty);
+
+ return Owned(new (Context) ObjCPropertyRefExpr(OMD, SMD, PType,
+ VK, OK,
+ MemberLoc, BaseExpr.take()));
+ }
+ }
+ // Use of id.member can only be for a property reference. Do not
+ // use the 'id' redefinition in this case.
+ if (IsArrow && ShouldTryAgainWithRedefinitionType(*this, BaseExpr))
+ return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
+ ObjCImpDecl, HasTemplateArgs);
+
+ return ExprError(Diag(MemberLoc, diag::err_property_not_found)
+ << MemberName << BaseType);
+ }
+
+ // 'Class', unqualified only.
+ if (OT->isObjCClass()) {
+ // Only works in a method declaration (??!).
+ ObjCMethodDecl *MD = getCurMethodDecl();
+ if (!MD) {
+ if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr))
+ return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
+ ObjCImpDecl, HasTemplateArgs);
+
+ goto fail;
+ }
+
+ // Also must look for a getter name which uses property syntax.
+ Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
+ ObjCInterfaceDecl *IFace = MD->getClassInterface();
+ ObjCMethodDecl *Getter;
+ if ((Getter = IFace->lookupClassMethod(Sel))) {
+ // Check the use of this method.
+ if (DiagnoseUseOfDecl(Getter, MemberLoc))
+ return ExprError();
+ } else
+ Getter = IFace->lookupPrivateMethod(Sel, false);
+ // If we found a getter then this may be a valid dot-reference, we
+ // will look for the matching setter, in case it is needed.
+ Selector SetterSel =
+ SelectorTable::constructSetterName(PP.getIdentifierTable(),
+ PP.getSelectorTable(), Member);
+ ObjCMethodDecl *Setter = IFace->lookupClassMethod(SetterSel);
+ if (!Setter) {
+ // If this reference is in an @implementation, also check for 'private'
+ // methods.
+ Setter = IFace->lookupPrivateMethod(SetterSel, false);
+ }
+ // Look through local category implementations associated with the class.
+ if (!Setter)
+ Setter = IFace->getCategoryClassMethod(SetterSel);
+
+ if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc))
+ return ExprError();
+
+ if (Getter || Setter) {
+ QualType PType;
+
+ ExprValueKind VK = VK_LValue;
+ if (Getter) {
+ PType = getMessageSendResultType(QualType(OT, 0), Getter, true,
+ false);
+ if (!getLangOptions().CPlusPlus && PType.isCForbiddenLValueType())
+ VK = VK_RValue;
+ } else {
+ // Get the expression type from Setter's incoming parameter.
+ PType = (*(Setter->param_end() -1))->getType();
+ }
+ ExprObjectKind OK = (VK == VK_RValue ? OK_Ordinary : OK_ObjCProperty);
+
+ // FIXME: we must check that the setter has property type.
+ return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter,
+ PType, VK, OK,
+ MemberLoc, BaseExpr.take()));
+ }
+
+ if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr))
+ return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
+ ObjCImpDecl, HasTemplateArgs);
+
+ return ExprError(Diag(MemberLoc, diag::err_property_not_found)
+ << MemberName << BaseType);
+ }
+
+ // Normal property access.
+ return HandleExprPropertyRefExpr(OPT, BaseExpr.get(), OpLoc,
+ MemberName, MemberLoc,
+ SourceLocation(), QualType(), false);
+ }
+
+ // Handle 'field access' to vectors, such as 'V.xx'.
+ if (BaseType->isExtVectorType()) {
+ // FIXME: this expr should store IsArrow.
+ IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
+ ExprValueKind VK = (IsArrow ? VK_LValue : BaseExpr.get()->getValueKind());
+ QualType ret = CheckExtVectorComponent(*this, BaseType, VK, OpLoc,
+ Member, MemberLoc);
+ if (ret.isNull())
+ return ExprError();
+
+ return Owned(new (Context) ExtVectorElementExpr(ret, VK, BaseExpr.take(),
+ *Member, MemberLoc));
+ }
+
+ // Adjust builtin-sel to the appropriate redefinition type if that's
+ // not just a pointer to builtin-sel again.
+ if (IsArrow &&
+ BaseType->isSpecificBuiltinType(BuiltinType::ObjCSel) &&
+ !Context.ObjCSelRedefinitionType->isObjCSelType()) {
+ BaseExpr = ImpCastExprToType(BaseExpr.take(), Context.ObjCSelRedefinitionType,
+ CK_BitCast);
+ return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
+ ObjCImpDecl, HasTemplateArgs);
+ }
+
+ // Failure cases.
+ fail:
+
+ // Recover from dot accesses to pointers, e.g.:
+ // type *foo;
+ // foo.bar
+ // This is actually well-formed in two cases:
+ // - 'type' is an Objective C type
+ // - 'bar' is a pseudo-destructor name which happens to refer to
+ // the appropriate pointer type
+ if (const PointerType *Ptr = BaseType->getAs<PointerType>()) {
+ if (!IsArrow && Ptr->getPointeeType()->isRecordType() &&
+ MemberName.getNameKind() != DeclarationName::CXXDestructorName) {
+ Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
+ << BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange()
+ << FixItHint::CreateReplacement(OpLoc, "->");
+
+ // Recurse as an -> access.
+ IsArrow = true;
+ return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
+ ObjCImpDecl, HasTemplateArgs);
+ }
+ }
+
+ // If the user is trying to apply -> or . to a function name, it's probably
+ // because they forgot parentheses to call that function.
+ QualType ZeroArgCallTy;
+ UnresolvedSet<4> Overloads;
+ if (isExprCallable(*BaseExpr.get(), ZeroArgCallTy, Overloads)) {
+ if (ZeroArgCallTy.isNull()) {
+ Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call)
+ << (Overloads.size() > 1) << 0 << BaseExpr.get()->getSourceRange();
+ UnresolvedSet<2> PlausibleOverloads;
+ for (OverloadExpr::decls_iterator It = Overloads.begin(),
+ DeclsEnd = Overloads.end(); It != DeclsEnd; ++It) {
+ const FunctionDecl *OverloadDecl = cast<FunctionDecl>(*It);
+ QualType OverloadResultTy = OverloadDecl->getResultType();
+ if ((!IsArrow && OverloadResultTy->isRecordType()) ||
+ (IsArrow && OverloadResultTy->isPointerType() &&
+ OverloadResultTy->getPointeeType()->isRecordType()))
+ PlausibleOverloads.addDecl(It.getDecl());
+ }
+ NoteOverloads(PlausibleOverloads, BaseExpr.get()->getExprLoc());
+ return ExprError();
+ }
+ if ((!IsArrow && ZeroArgCallTy->isRecordType()) ||
+ (IsArrow && ZeroArgCallTy->isPointerType() &&
+ ZeroArgCallTy->getPointeeType()->isRecordType())) {
+ // At this point, we know BaseExpr looks like it's potentially callable
+ // with 0 arguments, and that it returns something of a reasonable type,
+ // so we can emit a fixit and carry on pretending that BaseExpr was
+ // actually a CallExpr.
+ SourceLocation ParenInsertionLoc =
+ PP.getLocForEndOfToken(BaseExpr.get()->getLocEnd());
+ Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call)
+ << (Overloads.size() > 1) << 1 << BaseExpr.get()->getSourceRange()
+ << FixItHint::CreateInsertion(ParenInsertionLoc, "()");
+ // FIXME: Try this before emitting the fixit, and suppress diagnostics
+ // while doing so.
+ ExprResult NewBase =
+ ActOnCallExpr(0, BaseExpr.take(), ParenInsertionLoc,
+ MultiExprArg(*this, 0, 0),
+ ParenInsertionLoc.getFileLocWithOffset(1));
+ if (NewBase.isInvalid())
+ return ExprError();
+ BaseExpr = NewBase;
+ BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take());
+ return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
+ ObjCImpDecl, HasTemplateArgs);
+ }
+ }
+
+ Diag(MemberLoc, diag::err_typecheck_member_reference_struct_union)
+ << BaseType << BaseExpr.get()->getSourceRange();
+
+ return ExprError();
+}
+
+/// The main callback when the parser finds something like
+/// expression . [nested-name-specifier] identifier
+/// expression -> [nested-name-specifier] identifier
+/// where 'identifier' encompasses a fairly broad spectrum of
+/// possibilities, including destructor and operator references.
+///
+/// \param OpKind either tok::arrow or tok::period
+/// \param HasTrailingLParen whether the next token is '(', which
+/// is used to diagnose mis-uses of special members that can
+/// only be called
+/// \param ObjCImpDecl the current ObjC @implementation decl;
+/// this is an ugly hack around the fact that ObjC @implementations
+/// aren't properly put in the context chain
+ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ CXXScopeSpec &SS,
+ UnqualifiedId &Id,
+ Decl *ObjCImpDecl,
+ bool HasTrailingLParen) {
+ if (SS.isSet() && SS.isInvalid())
+ return ExprError();
+
+ // Warn about the explicit constructor calls Microsoft extension.
+ if (getLangOptions().Microsoft &&
+ Id.getKind() == UnqualifiedId::IK_ConstructorName)
+ Diag(Id.getSourceRange().getBegin(),
+ diag::ext_ms_explicit_constructor_call);
+
+ TemplateArgumentListInfo TemplateArgsBuffer;
+
+ // Decompose the name into its component parts.
+ DeclarationNameInfo NameInfo;
+ const TemplateArgumentListInfo *TemplateArgs;
+ DecomposeUnqualifiedId(Id, TemplateArgsBuffer,
+ NameInfo, TemplateArgs);
+
+ DeclarationName Name = NameInfo.getName();
+ bool IsArrow = (OpKind == tok::arrow);
+
+ NamedDecl *FirstQualifierInScope
+ = (!SS.isSet() ? 0 : FindFirstQualifierInScope(S,
+ static_cast<NestedNameSpecifier*>(SS.getScopeRep())));
+
+ // This is a postfix expression, so get rid of ParenListExprs.
+ ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Base);
+ if (Result.isInvalid()) return ExprError();
+ Base = Result.take();
+
+ if (Base->getType()->isDependentType() || Name.isDependentName() ||
+ isDependentScopeSpecifier(SS)) {
+ Result = ActOnDependentMemberExpr(Base, Base->getType(),
+ IsArrow, OpLoc,
+ SS, FirstQualifierInScope,
+ NameInfo, TemplateArgs);
+ } else {
+ LookupResult R(*this, NameInfo, LookupMemberName);
+ ExprResult BaseResult = Owned(Base);
+ Result = LookupMemberExpr(R, BaseResult, IsArrow, OpLoc,
+ SS, ObjCImpDecl, TemplateArgs != 0);
+ if (BaseResult.isInvalid())
+ return ExprError();
+ Base = BaseResult.take();
+
+ if (Result.isInvalid()) {
+ Owned(Base);
+ return ExprError();
+ }
+
+ if (Result.get()) {
+ // The only way a reference to a destructor can be used is to
+ // immediately call it, which falls into this case. If the
+ // next token is not a '(', produce a diagnostic and build the
+ // call now.
+ if (!HasTrailingLParen &&
+ Id.getKind() == UnqualifiedId::IK_DestructorName)
+ return DiagnoseDtorReference(NameInfo.getLoc(), Result.get());
+
+ return move(Result);
+ }
+
+ Result = BuildMemberReferenceExpr(Base, Base->getType(),
+ OpLoc, IsArrow, SS, FirstQualifierInScope,
+ R, TemplateArgs);
+ }
+
+ return move(Result);
+}
+
+static ExprResult
+BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow,
+ const CXXScopeSpec &SS, FieldDecl *Field,
+ DeclAccessPair FoundDecl,
+ const DeclarationNameInfo &MemberNameInfo) {
+ // x.a is an l-value if 'a' has a reference type. Otherwise:
+ // x.a is an l-value/x-value/pr-value if the base is (and note
+ // that *x is always an l-value), except that if the base isn't
+ // an ordinary object then we must have an rvalue.
+ ExprValueKind VK = VK_LValue;
+ ExprObjectKind OK = OK_Ordinary;
+ if (!IsArrow) {
+ if (BaseExpr->getObjectKind() == OK_Ordinary)
+ VK = BaseExpr->getValueKind();
+ else
+ VK = VK_RValue;
+ }
+ if (VK != VK_RValue && Field->isBitField())
+ OK = OK_BitField;
+
+ // Figure out the type of the member; see C99 6.5.2.3p3, C++ [expr.ref]
+ QualType MemberType = Field->getType();
+ if (const ReferenceType *Ref = MemberType->getAs<ReferenceType>()) {
+ MemberType = Ref->getPointeeType();
+ VK = VK_LValue;
+ } else {
+ QualType BaseType = BaseExpr->getType();
+ if (IsArrow) BaseType = BaseType->getAs<PointerType>()->getPointeeType();
+
+ Qualifiers BaseQuals = BaseType.getQualifiers();
+
+ // GC attributes are never picked up by members.
+ BaseQuals.removeObjCGCAttr();
+
+ // CVR attributes from the base are picked up by members,
+ // except that 'mutable' members don't pick up 'const'.
+ if (Field->isMutable()) BaseQuals.removeConst();
+
+ Qualifiers MemberQuals
+ = S.Context.getCanonicalType(MemberType).getQualifiers();
+
+ // TR 18037 does not allow fields to be declared with address spaces.
+ assert(!MemberQuals.hasAddressSpace());
+
+ Qualifiers Combined = BaseQuals + MemberQuals;
+ if (Combined != MemberQuals)
+ MemberType = S.Context.getQualifiedType(MemberType, Combined);
+ }
+
+ S.MarkDeclarationReferenced(MemberNameInfo.getLoc(), Field);
+ ExprResult Base =
+ S.PerformObjectMemberConversion(BaseExpr, SS.getScopeRep(),
+ FoundDecl, Field);
+ if (Base.isInvalid())
+ return ExprError();
+ return S.Owned(BuildMemberExpr(S.Context, Base.take(), IsArrow, SS,
+ Field, FoundDecl, MemberNameInfo,
+ MemberType, VK, OK));
+}
+
+/// Builds an implicit member access expression. The current context
+/// is known to be an instance method, and the given unqualified lookup
+/// set is known to contain only instance members, at least one of which
+/// is from an appropriate type.
+ExprResult
+Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS,
+ LookupResult &R,
+ const TemplateArgumentListInfo *TemplateArgs,
+ bool IsKnownInstance) {
+ assert(!R.empty() && !R.isAmbiguous());
+
+ SourceLocation loc = R.getNameLoc();
+
+ // We may have found a field within an anonymous union or struct
+ // (C++ [class.union]).
+ // FIXME: template-ids inside anonymous structs?
+ if (IndirectFieldDecl *FD = R.getAsSingle<IndirectFieldDecl>())
+ return BuildAnonymousStructUnionMemberReference(SS, R.getNameLoc(), FD);
+
+ // If this is known to be an instance access, go ahead and build an
+ // implicit 'this' expression now.
+ // 'this' expression now.
+ QualType ThisTy = getAndCaptureCurrentThisType();
+ assert(!ThisTy.isNull() && "didn't correctly pre-flight capture of 'this'");
+
+ Expr *baseExpr = 0; // null signifies implicit access
+ if (IsKnownInstance) {
+ SourceLocation Loc = R.getNameLoc();
+ if (SS.getRange().isValid())
+ Loc = SS.getRange().getBegin();
+ baseExpr = new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/true);
+ }
+
+ return BuildMemberReferenceExpr(baseExpr, ThisTy,
+ /*OpLoc*/ SourceLocation(),
+ /*IsArrow*/ true,
+ SS,
+ /*FirstQualifierInScope*/ 0,
+ R, TemplateArgs);
+}
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index cb5c1e0d0cbe..02a4682cc840 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -19,6 +19,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/AST/StmtVisitor.h"
#include "clang/AST/TypeLoc.h"
#include "llvm/ADT/SmallString.h"
#include "clang/Lex/Preprocessor.h"
@@ -62,7 +63,7 @@ ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs,
// Create the aggregate string with the appropriate content and location
// information.
- S = StringLiteral::Create(Context, &StrBuf[0], StrBuf.size(),
+ S = StringLiteral::Create(Context, StrBuf,
/*Wide=*/false, /*Pascal=*/false,
Context.getPointerType(Context.CharTy),
&StrLocs[0], StrLocs.size());
@@ -127,7 +128,8 @@ ExprResult Sema::BuildObjCEncodeExpression(SourceLocation AtLoc,
if (EncodedType->isDependentType())
StrTy = Context.DependentTy;
else {
- if (!EncodedType->getAsArrayTypeUnsafe()) // Incomplete array is handled.
+ if (!EncodedType->getAsArrayTypeUnsafe() && //// Incomplete array is handled.
+ !EncodedType->isVoidType()) // void is handled too.
if (RequireCompleteType(AtLoc, EncodedType,
PDiag(diag::err_incomplete_type_objc_at_encode)
<< EncodedTypeInfo->getTypeLoc().getSourceRange()))
@@ -176,12 +178,39 @@ ExprResult Sema::ParseObjCSelectorExpression(Selector Sel,
SourceRange(LParenLoc, RParenLoc));
if (!Method)
Diag(SelLoc, diag::warn_undeclared_selector) << Sel;
+
+ if (!Method ||
+ Method->getImplementationControl() != ObjCMethodDecl::Optional) {
+ llvm::DenseMap<Selector, SourceLocation>::iterator Pos
+ = ReferencedSelectors.find(Sel);
+ if (Pos == ReferencedSelectors.end())
+ ReferencedSelectors.insert(std::make_pair(Sel, SelLoc));
+ }
- llvm::DenseMap<Selector, SourceLocation>::iterator Pos
- = ReferencedSelectors.find(Sel);
- if (Pos == ReferencedSelectors.end())
- ReferencedSelectors.insert(std::make_pair(Sel, SelLoc));
-
+ // In ARC, forbid the user from using @selector for
+ // retain/release/autorelease/dealloc/retainCount.
+ if (getLangOptions().ObjCAutoRefCount) {
+ switch (Sel.getMethodFamily()) {
+ case OMF_retain:
+ case OMF_release:
+ case OMF_autorelease:
+ case OMF_retainCount:
+ case OMF_dealloc:
+ Diag(AtLoc, diag::err_arc_illegal_selector) <<
+ Sel << SourceRange(LParenLoc, RParenLoc);
+ break;
+
+ case OMF_None:
+ case OMF_alloc:
+ case OMF_copy:
+ case OMF_init:
+ case OMF_mutableCopy:
+ case OMF_new:
+ case OMF_self:
+ case OMF_performSelector:
+ break;
+ }
+ }
QualType Ty = Context.getObjCSelType();
return new (Context) ObjCSelectorExpr(Ty, Sel, AtLoc, RParenLoc);
}
@@ -321,11 +350,22 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
Args[i] = Result.take();
}
- unsigned DiagID = isClassMessage ? diag::warn_class_method_not_found :
- diag::warn_inst_method_not_found;
+ unsigned DiagID;
+ if (getLangOptions().ObjCAutoRefCount)
+ DiagID = diag::err_arc_method_not_found;
+ else
+ DiagID = isClassMessage ? diag::warn_class_method_not_found
+ : diag::warn_inst_method_not_found;
Diag(lbrac, DiagID)
<< Sel << isClassMessage << SourceRange(lbrac, rbrac);
- ReturnType = Context.getObjCIdType();
+
+ // In debuggers, we want to use __unknown_anytype for these
+ // results so that clients can cast them.
+ if (getLangOptions().DebuggerSupport) {
+ ReturnType = Context.UnknownAnyTy;
+ } else {
+ ReturnType = Context.getObjCIdType();
+ }
VK = VK_RValue;
return false;
}
@@ -404,17 +444,15 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
return IsError;
}
-bool Sema::isSelfExpr(Expr *RExpr) {
+bool Sema::isSelfExpr(Expr *receiver) {
// 'self' is objc 'self' in an objc method only.
DeclContext *DC = CurContext;
while (isa<BlockDecl>(DC))
DC = DC->getParent();
if (DC && !isa<ObjCMethodDecl>(DC))
return false;
- if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(RExpr))
- if (ICE->getCastKind() == CK_LValueToRValue)
- RExpr = ICE->getSubExpr();
- if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(RExpr))
+ receiver = receiver->IgnoreParenLValueCasts();
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(receiver))
if (DRE->getDecl()->getIdentifier() == &Context.Idents.get("self"))
return true;
return false;
@@ -489,7 +527,8 @@ ObjCMethodDecl *Sema::LookupMethodInQualifiedType(Selector Sel,
/// objective C interface. This is a property reference expression.
ExprResult Sema::
HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
- Expr *BaseExpr, DeclarationName MemberName,
+ Expr *BaseExpr, SourceLocation OpLoc,
+ DeclarationName MemberName,
SourceLocation MemberLoc,
SourceLocation SuperLoc, QualType SuperType,
bool Super) {
@@ -635,17 +674,19 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
}
// Attempt to correct for typos in property names.
- LookupResult Res(*this, MemberName, MemberLoc, LookupOrdinaryName);
- if (CorrectTypo(Res, 0, 0, IFace, false, CTC_NoKeywords, OPT) &&
- Res.getAsSingle<ObjCPropertyDecl>()) {
- DeclarationName TypoResult = Res.getLookupName();
+ TypoCorrection Corrected = CorrectTypo(
+ DeclarationNameInfo(MemberName, MemberLoc), LookupOrdinaryName, NULL,
+ NULL, IFace, false, CTC_NoKeywords, OPT);
+ if (ObjCPropertyDecl *Property =
+ Corrected.getCorrectionDeclAs<ObjCPropertyDecl>()) {
+ DeclarationName TypoResult = Corrected.getCorrection();
Diag(MemberLoc, diag::err_property_not_found_suggest)
<< MemberName << QualType(OPT, 0) << TypoResult
<< FixItHint::CreateReplacement(MemberLoc, TypoResult.getAsString());
- ObjCPropertyDecl *Property = Res.getAsSingle<ObjCPropertyDecl>();
Diag(Property->getLocation(), diag::note_previous_decl)
<< Property->getDeclName();
- return HandleExprPropertyRefExpr(OPT, BaseExpr, TypoResult, MemberLoc,
+ return HandleExprPropertyRefExpr(OPT, BaseExpr, OpLoc,
+ TypoResult, MemberLoc,
SuperLoc, SuperType, Super);
}
ObjCInterfaceDecl *ClassDeclared;
@@ -663,6 +704,11 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
return ExprError();
}
}
+ Diag(MemberLoc,
+ diag::err_ivar_access_using_property_syntax_suggest)
+ << MemberName << QualType(OPT, 0) << Ivar->getDeclName()
+ << FixItHint::CreateReplacement(OpLoc, "->");
+ return ExprError();
}
Diag(MemberLoc, diag::err_property_not_found)
@@ -699,7 +745,9 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
T = Context.getObjCObjectPointerType(T);
return HandleExprPropertyRefExpr(T->getAsObjCInterfacePointerType(),
- /*BaseExpr*/0, &propertyName,
+ /*BaseExpr*/0,
+ SourceLocation()/*OpLoc*/,
+ &propertyName,
propertyNameLoc,
receiverNameLoc, T, true);
}
@@ -862,29 +910,30 @@ Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S,
Method->getClassInterface()->getSuperClass())
CTC = CTC_ObjCMessageReceiver;
- if (DeclarationName Corrected = CorrectTypo(Result, S, 0, 0, false, CTC)) {
- if (Result.isSingleResult()) {
+ if (TypoCorrection Corrected = CorrectTypo(Result.getLookupNameInfo(),
+ Result.getLookupKind(), S, NULL,
+ NULL, false, CTC)) {
+ if (NamedDecl *ND = Corrected.getCorrectionDecl()) {
// If we found a declaration, correct when it refers to an Objective-C
// class.
- NamedDecl *ND = Result.getFoundDecl();
if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(ND)) {
Diag(NameLoc, diag::err_unknown_receiver_suggest)
- << Name << Result.getLookupName()
+ << Name << Corrected.getCorrection()
<< FixItHint::CreateReplacement(SourceRange(NameLoc),
ND->getNameAsString());
Diag(ND->getLocation(), diag::note_previous_decl)
- << Corrected;
+ << Corrected.getCorrection();
QualType T = Context.getObjCInterfaceType(Class);
TypeSourceInfo *TSInfo = Context.getTrivialTypeSourceInfo(T, NameLoc);
ReceiverType = CreateParsedType(T, TSInfo);
return ObjCClassMessage;
}
- } else if (Result.empty() && Corrected.getAsIdentifierInfo() &&
- Corrected.getAsIdentifierInfo()->isStr("super")) {
+ } else if (Corrected.isKeyword() &&
+ Corrected.getCorrectionAsIdentifierInfo()->isStr("super")) {
// If we've found the keyword "super", this is a send to super.
Diag(NameLoc, diag::err_unknown_receiver_suggest)
- << Name << Corrected
+ << Name << Corrected.getCorrection()
<< FixItHint::CreateReplacement(SourceRange(NameLoc), "super");
return ObjCSuperMessage;
}
@@ -1013,11 +1062,16 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
// Find the method we are messaging.
if (!Method) {
if (Class->isForwardDecl()) {
+ if (getLangOptions().ObjCAutoRefCount) {
+ Diag(Loc, diag::err_arc_receiver_forward_class) << ReceiverType;
+ } else {
+ Diag(Loc, diag::warn_receiver_forward_class) << Class->getDeclName();
+ }
+
// A forward class used in messaging is treated as a 'Class'
- Diag(Loc, diag::warn_receiver_forward_class) << Class->getDeclName();
Method = LookupFactoryMethodInGlobalPool(Sel,
SourceRange(LBracLoc, RBracLoc));
- if (Method)
+ if (Method && !getLangOptions().ObjCAutoRefCount)
Diag(Method->getLocation(), diag::note_method_sent_forward_class)
<< Method->getDeclName();
}
@@ -1236,6 +1290,14 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
= ReceiverType->getAsObjCInterfacePointerType()) {
// We allow sending a message to a pointer to an interface (an object).
ClassDecl = OCIType->getInterfaceDecl();
+
+ if (ClassDecl->isForwardDecl() && getLangOptions().ObjCAutoRefCount) {
+ Diag(Loc, diag::err_arc_receiver_forward_instance)
+ << OCIType->getPointeeType()
+ << (Receiver ? Receiver->getSourceRange() : SourceRange(SuperLoc));
+ return ExprError();
+ }
+
// FIXME: consider using LookupInstanceMethodInGlobalPool, since it will be
// faster than the following method (which can do *many* linear searches).
// The idea is to add class info to MethodPool.
@@ -1250,6 +1312,12 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
// If we have implementations in scope, check "private" methods.
Method = LookupPrivateInstanceMethod(Sel, ClassDecl);
+ if (!Method && getLangOptions().ObjCAutoRefCount) {
+ Diag(Loc, diag::err_arc_may_not_respond)
+ << OCIType->getPointeeType() << Sel;
+ return ExprError();
+ }
+
if (!Method && (!Receiver || !isSelfExpr(Receiver))) {
// If we still haven't found a method, look in the global pool. This
// behavior isn't very desirable, however we need it for GCC
@@ -1267,10 +1335,12 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
}
if (Method && DiagnoseUseOfDecl(Method, Loc, forwardClass))
return ExprError();
- } else if (!Context.getObjCIdType().isNull() &&
+ } else if (!getLangOptions().ObjCAutoRefCount &&
+ !Context.getObjCIdType().isNull() &&
(ReceiverType->isPointerType() ||
ReceiverType->isIntegerType())) {
// Implicitly convert integers and pointers to 'id' but emit a warning.
+ // But not in ARC.
Diag(Loc, diag::warn_bad_receiver_type)
<< ReceiverType
<< Receiver->getSourceRange();
@@ -1332,8 +1402,84 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
diag::err_illegal_message_expr_incomplete_type))
return ExprError();
+ // In ARC, forbid the user from sending messages to
+ // retain/release/autorelease/dealloc/retainCount explicitly.
+ if (getLangOptions().ObjCAutoRefCount) {
+ ObjCMethodFamily family =
+ (Method ? Method->getMethodFamily() : Sel.getMethodFamily());
+ switch (family) {
+ case OMF_init:
+ if (Method)
+ checkInitMethod(Method, ReceiverType);
+
+ case OMF_None:
+ case OMF_alloc:
+ case OMF_copy:
+ case OMF_mutableCopy:
+ case OMF_new:
+ case OMF_self:
+ break;
+
+ case OMF_dealloc:
+ case OMF_retain:
+ case OMF_release:
+ case OMF_autorelease:
+ case OMF_retainCount:
+ Diag(Loc, diag::err_arc_illegal_explicit_message)
+ << Sel << SelectorLoc;
+ break;
+
+ case OMF_performSelector:
+ if (Method && NumArgs >= 1) {
+ if (ObjCSelectorExpr *SelExp = dyn_cast<ObjCSelectorExpr>(Args[0])) {
+ Selector ArgSel = SelExp->getSelector();
+ ObjCMethodDecl *SelMethod =
+ LookupInstanceMethodInGlobalPool(ArgSel,
+ SelExp->getSourceRange());
+ if (!SelMethod)
+ SelMethod =
+ LookupFactoryMethodInGlobalPool(ArgSel,
+ SelExp->getSourceRange());
+ if (SelMethod) {
+ ObjCMethodFamily SelFamily = SelMethod->getMethodFamily();
+ switch (SelFamily) {
+ case OMF_alloc:
+ case OMF_copy:
+ case OMF_mutableCopy:
+ case OMF_new:
+ case OMF_self:
+ case OMF_init:
+ // Issue error, unless ns_returns_not_retained.
+ if (!SelMethod->hasAttr<NSReturnsNotRetainedAttr>()) {
+ // selector names a +1 method
+ Diag(SelectorLoc,
+ diag::err_arc_perform_selector_retains);
+ Diag(SelMethod->getLocation(), diag::note_method_declared_at);
+ }
+ break;
+ default:
+ // +0 call. OK. unless ns_returns_retained.
+ if (SelMethod->hasAttr<NSReturnsRetainedAttr>()) {
+ // selector names a +1 method
+ Diag(SelectorLoc,
+ diag::err_arc_perform_selector_retains);
+ Diag(SelMethod->getLocation(), diag::note_method_declared_at);
+ }
+ break;
+ }
+ }
+ } else {
+ // error (may leak).
+ Diag(SelectorLoc, diag::warn_arc_perform_selector_leaks);
+ Diag(Args[0]->getExprLoc(), diag::note_used_here);
+ }
+ }
+ break;
+ }
+ }
+
// Construct the appropriate ObjCMessageExpr instance.
- Expr *Result;
+ ObjCMessageExpr *Result;
if (SuperLoc.isValid())
Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc,
SuperLoc, /*IsInstanceSuper=*/true,
@@ -1343,6 +1489,27 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc,
Receiver, Sel, SelectorLoc, Method,
Args, NumArgs, RBracLoc);
+
+ if (getLangOptions().ObjCAutoRefCount) {
+ // In ARC, annotate delegate init calls.
+ if (Result->getMethodFamily() == OMF_init &&
+ (SuperLoc.isValid() || isSelfExpr(Receiver))) {
+ // Only consider init calls *directly* in init implementations,
+ // not within blocks.
+ ObjCMethodDecl *method = dyn_cast<ObjCMethodDecl>(CurContext);
+ if (method && method->getMethodFamily() == OMF_init) {
+ // The implicit assignment to self means we also don't want to
+ // consume the result.
+ Result->setDelegateInitCall(true);
+ return Owned(Result);
+ }
+ }
+
+ // In ARC, check for message sends which are likely to introduce
+ // retain cycles.
+ checkRetainCycles(Result);
+ }
+
return MaybeBindToTemporary(Result);
}
@@ -1364,3 +1531,393 @@ ExprResult Sema::ActOnInstanceMessage(Scope *S,
LBracLoc, SelectorLoc, RBracLoc, move(Args));
}
+enum ARCConversionTypeClass {
+ ACTC_none,
+ ACTC_retainable,
+ ACTC_indirectRetainable
+};
+static ARCConversionTypeClass classifyTypeForARCConversion(QualType type) {
+ ARCConversionTypeClass ACTC = ACTC_retainable;
+
+ // Ignore an outermost reference type.
+ if (const ReferenceType *ref = type->getAs<ReferenceType>())
+ type = ref->getPointeeType();
+
+ // Drill through pointers and arrays recursively.
+ while (true) {
+ if (const PointerType *ptr = type->getAs<PointerType>()) {
+ type = ptr->getPointeeType();
+ } else if (const ArrayType *array = type->getAsArrayTypeUnsafe()) {
+ type = QualType(array->getElementType()->getBaseElementTypeUnsafe(), 0);
+ } else {
+ break;
+ }
+ ACTC = ACTC_indirectRetainable;
+ }
+
+ if (!type->isObjCRetainableType()) return ACTC_none;
+ return ACTC;
+}
+
+namespace {
+ /// Return true if the given expression can be reasonably converted
+ /// between a retainable pointer type and a C pointer type.
+ struct ARCCastChecker : StmtVisitor<ARCCastChecker, bool> {
+ ASTContext &Context;
+ ARCCastChecker(ASTContext &Context) : Context(Context) {}
+ bool VisitStmt(Stmt *s) {
+ return false;
+ }
+ bool VisitExpr(Expr *e) {
+ return e->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull);
+ }
+
+ bool VisitParenExpr(ParenExpr *e) {
+ return Visit(e->getSubExpr());
+ }
+ bool VisitCastExpr(CastExpr *e) {
+ switch (e->getCastKind()) {
+ case CK_NullToPointer:
+ return true;
+ case CK_NoOp:
+ case CK_LValueToRValue:
+ case CK_BitCast:
+ case CK_AnyPointerToObjCPointerCast:
+ case CK_AnyPointerToBlockPointerCast:
+ return Visit(e->getSubExpr());
+ default:
+ return false;
+ }
+ }
+ bool VisitUnaryExtension(UnaryOperator *e) {
+ return Visit(e->getSubExpr());
+ }
+ bool VisitBinComma(BinaryOperator *e) {
+ return Visit(e->getRHS());
+ }
+ bool VisitConditionalOperator(ConditionalOperator *e) {
+ // Conditional operators are okay if both sides are okay.
+ return Visit(e->getTrueExpr()) && Visit(e->getFalseExpr());
+ }
+ bool VisitObjCStringLiteral(ObjCStringLiteral *e) {
+ // Always white-list Objective-C string literals.
+ return true;
+ }
+ bool VisitStmtExpr(StmtExpr *e) {
+ return Visit(e->getSubStmt()->body_back());
+ }
+ bool VisitDeclRefExpr(DeclRefExpr *e) {
+ // White-list references to global extern strings from system
+ // headers.
+ if (VarDecl *var = dyn_cast<VarDecl>(e->getDecl()))
+ if (var->getStorageClass() == SC_Extern &&
+ var->getType().isConstQualified() &&
+ Context.getSourceManager().isInSystemHeader(var->getLocation()))
+ return true;
+ return false;
+ }
+ };
+}
+
+bool
+Sema::ValidObjCARCNoBridgeCastExpr(Expr *&Exp, QualType castType) {
+ Expr *NewExp = Exp->IgnoreParenCasts();
+
+ if (!isa<ObjCMessageExpr>(NewExp) && !isa<ObjCPropertyRefExpr>(NewExp)
+ && !isa<CallExpr>(NewExp))
+ return false;
+ ObjCMethodDecl *method = 0;
+ bool MethodReturnsPlusOne = false;
+
+ if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(NewExp)) {
+ method = PRE->getExplicitProperty()->getGetterMethodDecl();
+ }
+ else if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(NewExp))
+ method = ME->getMethodDecl();
+ else {
+ CallExpr *CE = cast<CallExpr>(NewExp);
+ Decl *CallDecl = CE->getCalleeDecl();
+ if (!CallDecl)
+ return false;
+ if (CallDecl->hasAttr<CFReturnsNotRetainedAttr>())
+ return true;
+ MethodReturnsPlusOne = CallDecl->hasAttr<CFReturnsRetainedAttr>();
+ if (!MethodReturnsPlusOne) {
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(CallDecl))
+ if (const IdentifierInfo *Id = ND->getIdentifier())
+ if (Id->isStr("__builtin___CFStringMakeConstantString"))
+ return true;
+ }
+ }
+
+ if (!MethodReturnsPlusOne) {
+ if (!method)
+ return false;
+ if (method->hasAttr<CFReturnsNotRetainedAttr>())
+ return true;
+ MethodReturnsPlusOne = method->hasAttr<CFReturnsRetainedAttr>();
+ if (!MethodReturnsPlusOne) {
+ ObjCMethodFamily family = method->getSelector().getMethodFamily();
+ switch (family) {
+ case OMF_alloc:
+ case OMF_copy:
+ case OMF_mutableCopy:
+ case OMF_new:
+ MethodReturnsPlusOne = true;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if (MethodReturnsPlusOne) {
+ TypeSourceInfo *TSInfo =
+ Context.getTrivialTypeSourceInfo(castType, SourceLocation());
+ ExprResult ExpRes = BuildObjCBridgedCast(SourceLocation(), OBC_BridgeTransfer,
+ SourceLocation(), TSInfo, Exp);
+ Exp = ExpRes.take();
+ }
+ return true;
+}
+
+void
+Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType,
+ Expr *&castExpr, CheckedConversionKind CCK) {
+ QualType castExprType = castExpr->getType();
+
+ ARCConversionTypeClass exprACTC = classifyTypeForARCConversion(castExprType);
+ ARCConversionTypeClass castACTC = classifyTypeForARCConversion(castType);
+ if (exprACTC == castACTC) return;
+ if (exprACTC && castType->isIntegralType(Context)) return;
+
+ // Allow casts between pointers to lifetime types (e.g., __strong id*)
+ // and pointers to void (e.g., cv void *). Casting from void* to lifetime*
+ // must be explicit.
+ if (const PointerType *CastPtr = castType->getAs<PointerType>()) {
+ if (const PointerType *CastExprPtr = castExprType->getAs<PointerType>()) {
+ QualType CastPointee = CastPtr->getPointeeType();
+ QualType CastExprPointee = CastExprPtr->getPointeeType();
+ if ((CCK != CCK_ImplicitConversion &&
+ CastPointee->isObjCIndirectLifetimeType() &&
+ CastExprPointee->isVoidType()) ||
+ (CastPointee->isVoidType() &&
+ CastExprPointee->isObjCIndirectLifetimeType()))
+ return;
+ }
+ }
+
+ if (ARCCastChecker(Context).Visit(castExpr))
+ return;
+
+ SourceLocation loc =
+ (castRange.isValid() ? castRange.getBegin() : castExpr->getExprLoc());
+
+ if (makeUnavailableInSystemHeader(loc,
+ "converts between Objective-C and C pointers in -fobjc-arc"))
+ return;
+
+ unsigned srcKind = 0;
+ switch (exprACTC) {
+ case ACTC_none:
+ srcKind = (castExprType->isPointerType() ? 1 : 0);
+ break;
+ case ACTC_retainable:
+ srcKind = (castExprType->isBlockPointerType() ? 2 : 3);
+ break;
+ case ACTC_indirectRetainable:
+ srcKind = 4;
+ break;
+ }
+
+ if (CCK == CCK_CStyleCast) {
+ // Check whether this could be fixed with a bridge cast.
+ SourceLocation AfterLParen = PP.getLocForEndOfToken(castRange.getBegin());
+ SourceLocation NoteLoc = AfterLParen.isValid()? AfterLParen : loc;
+
+ if (castType->isObjCARCBridgableType() &&
+ castExprType->isCARCBridgableType()) {
+ // explicit unbridged casts are allowed if the source of the cast is a
+ // message sent to an objc method (or property access)
+ if (ValidObjCARCNoBridgeCastExpr(castExpr, castType))
+ return;
+ Diag(loc, diag::err_arc_cast_requires_bridge)
+ << 2
+ << castExprType
+ << (castType->isBlockPointerType()? 1 : 0)
+ << castType
+ << castRange
+ << castExpr->getSourceRange();
+ Diag(NoteLoc, diag::note_arc_bridge)
+ << FixItHint::CreateInsertion(AfterLParen, "__bridge ");
+ Diag(NoteLoc, diag::note_arc_bridge_transfer)
+ << castExprType
+ << FixItHint::CreateInsertion(AfterLParen, "__bridge_transfer ");
+
+ return;
+ }
+
+ if (castType->isCARCBridgableType() &&
+ castExprType->isObjCARCBridgableType()){
+ Diag(loc, diag::err_arc_cast_requires_bridge)
+ << (castExprType->isBlockPointerType()? 1 : 0)
+ << castExprType
+ << 2
+ << castType
+ << castRange
+ << castExpr->getSourceRange();
+
+ Diag(NoteLoc, diag::note_arc_bridge)
+ << FixItHint::CreateInsertion(AfterLParen, "__bridge ");
+ Diag(NoteLoc, diag::note_arc_bridge_retained)
+ << castType
+ << FixItHint::CreateInsertion(AfterLParen, "__bridge_retained ");
+ return;
+ }
+ }
+
+ Diag(loc, diag::err_arc_mismatched_cast)
+ << (CCK != CCK_ImplicitConversion) << srcKind << castExprType << castType
+ << castRange << castExpr->getSourceRange();
+}
+
+bool Sema::CheckObjCARCUnavailableWeakConversion(QualType castType,
+ QualType exprType) {
+ QualType canCastType =
+ Context.getCanonicalType(castType).getUnqualifiedType();
+ QualType canExprType =
+ Context.getCanonicalType(exprType).getUnqualifiedType();
+ if (isa<ObjCObjectPointerType>(canCastType) &&
+ castType.getObjCLifetime() == Qualifiers::OCL_Weak &&
+ canExprType->isObjCObjectPointerType()) {
+ if (const ObjCObjectPointerType *ObjT =
+ canExprType->getAs<ObjCObjectPointerType>())
+ if (ObjT->getInterfaceDecl()->isArcWeakrefUnavailable())
+ return false;
+ }
+ return true;
+}
+
+/// Look for an ObjCReclaimReturnedObject cast and destroy it.
+static Expr *maybeUndoReclaimObject(Expr *e) {
+ // For now, we just undo operands that are *immediately* reclaim
+ // expressions, which prevents the vast majority of potential
+ // problems here. To catch them all, we'd need to rebuild arbitrary
+ // value-propagating subexpressions --- we can't reliably rebuild
+ // in-place because of expression sharing.
+ if (ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(e))
+ if (ice->getCastKind() == CK_ObjCReclaimReturnedObject)
+ return ice->getSubExpr();
+
+ return e;
+}
+
+ExprResult Sema::BuildObjCBridgedCast(SourceLocation LParenLoc,
+ ObjCBridgeCastKind Kind,
+ SourceLocation BridgeKeywordLoc,
+ TypeSourceInfo *TSInfo,
+ Expr *SubExpr) {
+ QualType T = TSInfo->getType();
+ QualType FromType = SubExpr->getType();
+
+ bool MustConsume = false;
+ if (T->isDependentType() || SubExpr->isTypeDependent()) {
+ // Okay: we'll build a dependent expression type.
+ } else if (T->isObjCARCBridgableType() && FromType->isCARCBridgableType()) {
+ // Casting CF -> id
+ switch (Kind) {
+ case OBC_Bridge:
+ break;
+
+ case OBC_BridgeRetained:
+ Diag(BridgeKeywordLoc, diag::err_arc_bridge_cast_wrong_kind)
+ << 2
+ << FromType
+ << (T->isBlockPointerType()? 1 : 0)
+ << T
+ << SubExpr->getSourceRange()
+ << Kind;
+ Diag(BridgeKeywordLoc, diag::note_arc_bridge)
+ << FixItHint::CreateReplacement(BridgeKeywordLoc, "__bridge");
+ Diag(BridgeKeywordLoc, diag::note_arc_bridge_transfer)
+ << FromType
+ << FixItHint::CreateReplacement(BridgeKeywordLoc,
+ "__bridge_transfer ");
+
+ Kind = OBC_Bridge;
+ break;
+
+ case OBC_BridgeTransfer:
+ // We must consume the Objective-C object produced by the cast.
+ MustConsume = true;
+ break;
+ }
+ } else if (T->isCARCBridgableType() && FromType->isObjCARCBridgableType()) {
+ // Okay: id -> CF
+ switch (Kind) {
+ case OBC_Bridge:
+ // Reclaiming a value that's going to be __bridge-casted to CF
+ // is very dangerous, so we don't do it.
+ SubExpr = maybeUndoReclaimObject(SubExpr);
+ break;
+
+ case OBC_BridgeRetained:
+ // Produce the object before casting it.
+ SubExpr = ImplicitCastExpr::Create(Context, FromType,
+ CK_ObjCProduceObject,
+ SubExpr, 0, VK_RValue);
+ break;
+
+ case OBC_BridgeTransfer:
+ Diag(BridgeKeywordLoc, diag::err_arc_bridge_cast_wrong_kind)
+ << (FromType->isBlockPointerType()? 1 : 0)
+ << FromType
+ << 2
+ << T
+ << SubExpr->getSourceRange()
+ << Kind;
+
+ Diag(BridgeKeywordLoc, diag::note_arc_bridge)
+ << FixItHint::CreateReplacement(BridgeKeywordLoc, "__bridge ");
+ Diag(BridgeKeywordLoc, diag::note_arc_bridge_retained)
+ << T
+ << FixItHint::CreateReplacement(BridgeKeywordLoc, "__bridge_retained ");
+
+ Kind = OBC_Bridge;
+ break;
+ }
+ } else {
+ Diag(LParenLoc, diag::err_arc_bridge_cast_incompatible)
+ << FromType << T << Kind
+ << SubExpr->getSourceRange()
+ << TSInfo->getTypeLoc().getSourceRange();
+ return ExprError();
+ }
+
+ Expr *Result = new (Context) ObjCBridgedCastExpr(LParenLoc, Kind,
+ BridgeKeywordLoc,
+ TSInfo, SubExpr);
+
+ if (MustConsume) {
+ ExprNeedsCleanups = true;
+ Result = ImplicitCastExpr::Create(Context, T, CK_ObjCConsumeObject, Result,
+ 0, VK_RValue);
+ }
+
+ return Result;
+}
+
+ExprResult Sema::ActOnObjCBridgedCast(Scope *S,
+ SourceLocation LParenLoc,
+ ObjCBridgeCastKind Kind,
+ SourceLocation BridgeKeywordLoc,
+ ParsedType Type,
+ SourceLocation RParenLoc,
+ Expr *SubExpr) {
+ TypeSourceInfo *TSInfo = 0;
+ QualType T = GetTypeFromParser(Type, &TSInfo);
+ if (!TSInfo)
+ TSInfo = Context.getTrivialTypeSourceInfo(T, LParenLoc);
+ return BuildObjCBridgedCast(LParenLoc, Kind, BridgeKeywordLoc, TSInfo,
+ SubExpr);
+}
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index a33f5d0b2f3e..9fbcbab0b7d0 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -769,7 +769,8 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
// subaggregate, brace elision is assumed and the initializer is
// considered for the initialization of the first member of
// the subaggregate.
- if (ElemType->isAggregateType() || ElemType->isVectorType()) {
+ if (!SemaRef.getLangOptions().OpenCL &&
+ (ElemType->isAggregateType() || ElemType->isVectorType())) {
CheckImplicitInitList(Entity, IList, ElemType, Index, StructuredList,
StructuredIndex);
++StructuredIndex;
@@ -1184,6 +1185,15 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity,
continue;
}
+ // Make sure we can use this declaration.
+ if (SemaRef.DiagnoseUseOfDecl(*Field,
+ IList->getInit(Index)->getLocStart())) {
+ ++Index;
+ ++Field;
+ hadError = true;
+ continue;
+ }
+
InitializedEntity MemberEntity =
InitializedEntity::InitializeMember(*Field, &Entity);
CheckSubElementType(MemberEntity, IList, Field->getType(), Index,
@@ -1443,19 +1453,23 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
// was a typo for another field name.
LookupResult R(SemaRef, FieldName, D->getFieldLoc(),
Sema::LookupMemberName);
- if (SemaRef.CorrectTypo(R, /*Scope=*/0, /*SS=*/0, RT->getDecl(), false,
- Sema::CTC_NoKeywords) &&
- (ReplacementField = R.getAsSingle<FieldDecl>()) &&
+ TypoCorrection Corrected = SemaRef.CorrectTypo(
+ DeclarationNameInfo(FieldName, D->getFieldLoc()),
+ Sema::LookupMemberName, /*Scope=*/NULL, /*SS=*/NULL,
+ RT->getDecl(), false, Sema::CTC_NoKeywords);
+ if ((ReplacementField = Corrected.getCorrectionDeclAs<FieldDecl>()) &&
ReplacementField->getDeclContext()->getRedeclContext()
->Equals(RT->getDecl())) {
+ std::string CorrectedStr(
+ Corrected.getAsString(SemaRef.getLangOptions()));
+ std::string CorrectedQuotedStr(
+ Corrected.getQuoted(SemaRef.getLangOptions()));
SemaRef.Diag(D->getFieldLoc(),
diag::err_field_designator_unknown_suggest)
- << FieldName << CurrentObjectType << R.getLookupName()
- << FixItHint::CreateReplacement(D->getFieldLoc(),
- R.getLookupName().getAsString());
+ << FieldName << CurrentObjectType << CorrectedQuotedStr
+ << FixItHint::CreateReplacement(D->getFieldLoc(), CorrectedStr);
SemaRef.Diag(ReplacementField->getLocation(),
- diag::note_previous_decl)
- << ReplacementField->getDeclName();
+ diag::note_previous_decl) << CorrectedQuotedStr;
} else {
SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_unknown)
<< FieldName << CurrentObjectType;
@@ -1499,6 +1513,12 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
StructuredList->setInitializedFieldInUnion(*Field);
}
+ // Make sure we can use this declaration.
+ if (SemaRef.DiagnoseUseOfDecl(*Field, D->getFieldLoc())) {
+ ++Index;
+ return true;
+ }
+
// Update the designator with the field declaration.
D->setField(*Field);
@@ -2029,10 +2049,10 @@ InitializedEntity InitializedEntity::InitializeBase(ASTContext &Context,
DeclarationName InitializedEntity::getName() const {
switch (getKind()) {
- case EK_Parameter:
- if (!VariableOrMember)
- return DeclarationName();
- // Fall through
+ case EK_Parameter: {
+ ParmVarDecl *D = reinterpret_cast<ParmVarDecl*>(Parameter & ~0x1);
+ return (D ? D->getDeclName() : DeclarationName());
+ }
case EK_Variable:
case EK_Member:
@@ -2057,10 +2077,12 @@ DeclarationName InitializedEntity::getName() const {
DeclaratorDecl *InitializedEntity::getDecl() const {
switch (getKind()) {
case EK_Variable:
- case EK_Parameter:
case EK_Member:
return VariableOrMember;
+ case EK_Parameter:
+ return reinterpret_cast<ParmVarDecl*>(Parameter & ~0x1);
+
case EK_Result:
case EK_Exception:
case EK_New:
@@ -2123,6 +2145,9 @@ void InitializationSequence::Step::Destroy() {
case SK_StringInit:
case SK_ObjCObjectConversion:
case SK_ArrayInit:
+ case SK_PassByIndirectCopyRestore:
+ case SK_PassByIndirectRestore:
+ case SK_ProduceObjCObject:
break;
case SK_ConversionSequence:
@@ -2131,7 +2156,7 @@ void InitializationSequence::Step::Destroy() {
}
bool InitializationSequence::isDirectReferenceBinding() const {
- return getKind() == ReferenceBinding && Steps.back().Kind == SK_BindReference;
+ return !Steps.empty() && Steps.back().Kind == SK_BindReference;
}
bool InitializationSequence::isAmbiguous() const {
@@ -2306,6 +2331,22 @@ void InitializationSequence::AddArrayInitStep(QualType T) {
Steps.push_back(S);
}
+void InitializationSequence::AddPassByIndirectCopyRestoreStep(QualType type,
+ bool shouldCopy) {
+ Step s;
+ s.Kind = (shouldCopy ? SK_PassByIndirectCopyRestore
+ : SK_PassByIndirectRestore);
+ s.Type = type;
+ Steps.push_back(s);
+}
+
+void InitializationSequence::AddProduceObjCObjectStep(QualType T) {
+ Step S;
+ S.Kind = SK_ProduceObjCObject;
+ S.Type = T;
+ Steps.push_back(S);
+}
+
void InitializationSequence::SetOverloadFailure(FailureKind Failure,
OverloadingResult Result) {
setSequenceKind(FailedSequence);
@@ -2317,6 +2358,33 @@ void InitializationSequence::SetOverloadFailure(FailureKind Failure,
// Attempt initialization
//===----------------------------------------------------------------------===//
+static void MaybeProduceObjCObject(Sema &S,
+ InitializationSequence &Sequence,
+ const InitializedEntity &Entity) {
+ if (!S.getLangOptions().ObjCAutoRefCount) return;
+
+ /// When initializing a parameter, produce the value if it's marked
+ /// __attribute__((ns_consumed)).
+ if (Entity.getKind() == InitializedEntity::EK_Parameter) {
+ if (!Entity.isParameterConsumed())
+ return;
+
+ assert(Entity.getType()->isObjCRetainableType() &&
+ "consuming an object of unretainable type?");
+ Sequence.AddProduceObjCObjectStep(Entity.getType());
+
+ /// When initializing a return value, if the return type is a
+ /// retainable type, then returns need to immediately retain the
+ /// object. If an autorelease is required, it will be done at the
+ /// last instant.
+ } else if (Entity.getKind() == InitializedEntity::EK_Result) {
+ if (!Entity.getType()->isObjCRetainableType())
+ return;
+
+ Sequence.AddProduceObjCObjectStep(Entity.getType());
+ }
+}
+
/// \brief Attempt list initialization (C++0x [dcl.init.list])
static void TryListInitialization(Sema &S,
const InitializedEntity &Entity,
@@ -2380,13 +2448,16 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
bool DerivedToBase;
bool ObjCConversion;
+ bool ObjCLifetimeConversion;
assert(!S.CompareReferenceRelationship(Initializer->getLocStart(),
T1, T2, DerivedToBase,
- ObjCConversion) &&
+ ObjCConversion,
+ ObjCLifetimeConversion) &&
"Must have incompatible references when binding via conversion");
(void)DerivedToBase;
(void)ObjCConversion;
-
+ (void)ObjCLifetimeConversion;
+
// Build the candidate set directly in the initialization sequence
// structure, so that it will persist if we fail.
OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet();
@@ -2513,10 +2584,12 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
bool NewDerivedToBase = false;
bool NewObjCConversion = false;
+ bool NewObjCLifetimeConversion = false;
Sema::ReferenceCompareResult NewRefRelationship
= S.CompareReferenceRelationship(DeclLoc, T1,
T2.getNonLValueExprType(S.Context),
- NewDerivedToBase, NewObjCConversion);
+ NewDerivedToBase, NewObjCConversion,
+ NewObjCLifetimeConversion);
if (NewRefRelationship == Sema::Ref_Incompatible) {
// If the type we've converted to is not reference-related to the
// type we're looking for, then there is another conversion step
@@ -2550,8 +2623,6 @@ static void TryReferenceInitialization(Sema &S,
const InitializationKind &Kind,
Expr *Initializer,
InitializationSequence &Sequence) {
- Sequence.setSequenceKind(InitializationSequence::ReferenceBinding);
-
QualType DestType = Entity.getType();
QualType cv1T1 = DestType->getAs<ReferenceType>()->getPointeeType();
Qualifiers T1Quals;
@@ -2584,10 +2655,11 @@ static void TryReferenceInitialization(Sema &S,
bool isRValueRef = !isLValueRef;
bool DerivedToBase = false;
bool ObjCConversion = false;
+ bool ObjCLifetimeConversion = false;
Expr::Classification InitCategory = Initializer->Classify(S.Context);
Sema::ReferenceCompareResult RefRelationship
= S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, DerivedToBase,
- ObjCConversion);
+ ObjCConversion, ObjCLifetimeConversion);
// C++0x [dcl.init.ref]p5:
// A reference to type "cv1 T1" is initialized by an expression of type
@@ -2746,11 +2818,15 @@ static void TryReferenceInitialization(Sema &S,
InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(cv1T1);
- if (S.TryImplicitConversion(Sequence, TempEntity, Initializer,
+ ImplicitConversionSequence ICS
+ = S.TryImplicitConversion(Initializer, TempEntity.getType(),
/*SuppressUserConversions*/ false,
AllowExplicit,
/*FIXME:InOverloadResolution=*/false,
- /*CStyle=*/Kind.isCStyleOrFunctionalCast())) {
+ /*CStyle=*/Kind.isCStyleOrFunctionalCast(),
+ /*AllowObjCWritebackConversion=*/false);
+
+ if (ICS.isBad()) {
// FIXME: Use the conversion function set stored in ICS to turn
// this into an overloading ambiguity diagnostic. However, we need
// to keep that set as an OverloadCandidateSet rather than as some
@@ -2764,6 +2840,8 @@ static void TryReferenceInitialization(Sema &S,
else
Sequence.SetFailed(InitializationSequence::FK_ReferenceInitFailed);
return;
+ } else {
+ Sequence.AddConversionSequenceStep(ICS, TempEntity.getType());
}
// [...] If T1 is reference-related to T2, cv1 must be the
@@ -2953,10 +3031,8 @@ static void TryDefaultInitialization(Sema &S,
// C++ [dcl.init]p6:
// To default-initialize an object of type T means:
// - if T is an array type, each element is default-initialized;
- QualType DestType = Entity.getType();
- while (const ArrayType *Array = S.Context.getAsArrayType(DestType))
- DestType = Array->getElementType();
-
+ QualType DestType = S.Context.getBaseElementType(Entity.getType());
+
// - if T is a (possibly cv-qualified) class type (Clause 9), the default
// constructor for T is called (and the initialization is ill-formed if
// T has no accessible default constructor);
@@ -2970,8 +3046,16 @@ static void TryDefaultInitialization(Sema &S,
// If a program calls for the default initialization of an object of
// a const-qualified type T, T shall be a class type with a user-provided
// default constructor.
- if (DestType.isConstQualified() && S.getLangOptions().CPlusPlus)
+ if (DestType.isConstQualified() && S.getLangOptions().CPlusPlus) {
Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst);
+ return;
+ }
+
+ // If the destination type has a lifetime property, zero-initialize it.
+ if (DestType.getQualifiers().hasObjCLifetime()) {
+ Sequence.AddZeroInitializationStep(Entity.getType());
+ return;
+ }
}
/// \brief Attempt a user-defined conversion between two types (C++ [dcl.init]),
@@ -3125,6 +3209,86 @@ static void TryUserDefinedConversion(Sema &S,
}
}
+/// The non-zero enum values here are indexes into diagnostic alternatives.
+enum InvalidICRKind { IIK_okay, IIK_nonlocal, IIK_nonscalar };
+
+/// Determines whether this expression is an acceptable ICR source.
+static InvalidICRKind isInvalidICRSource(ASTContext &C, Expr *e,
+ bool isAddressOf) {
+ // Skip parens.
+ e = e->IgnoreParens();
+
+ // Skip address-of nodes.
+ if (UnaryOperator *op = dyn_cast<UnaryOperator>(e)) {
+ if (op->getOpcode() == UO_AddrOf)
+ return isInvalidICRSource(C, op->getSubExpr(), /*addressof*/ true);
+
+ // Skip certain casts.
+ } else if (CastExpr *ce = dyn_cast<CastExpr>(e)) {
+ switch (ce->getCastKind()) {
+ case CK_Dependent:
+ case CK_BitCast:
+ case CK_LValueBitCast:
+ case CK_NoOp:
+ return isInvalidICRSource(C, ce->getSubExpr(), isAddressOf);
+
+ case CK_ArrayToPointerDecay:
+ return IIK_nonscalar;
+
+ case CK_NullToPointer:
+ return IIK_okay;
+
+ default:
+ break;
+ }
+
+ // If we have a declaration reference, it had better be a local variable.
+ } else if (isa<DeclRefExpr>(e) || isa<BlockDeclRefExpr>(e)) {
+ if (!isAddressOf) return IIK_nonlocal;
+
+ VarDecl *var;
+ if (isa<DeclRefExpr>(e)) {
+ var = dyn_cast<VarDecl>(cast<DeclRefExpr>(e)->getDecl());
+ if (!var) return IIK_nonlocal;
+ } else {
+ var = cast<BlockDeclRefExpr>(e)->getDecl();
+ }
+
+ return (var->hasLocalStorage() ? IIK_okay : IIK_nonlocal);
+
+ // If we have a conditional operator, check both sides.
+ } else if (ConditionalOperator *cond = dyn_cast<ConditionalOperator>(e)) {
+ if (InvalidICRKind iik = isInvalidICRSource(C, cond->getLHS(), isAddressOf))
+ return iik;
+
+ return isInvalidICRSource(C, cond->getRHS(), isAddressOf);
+
+ // These are never scalar.
+ } else if (isa<ArraySubscriptExpr>(e)) {
+ return IIK_nonscalar;
+
+ // Otherwise, it needs to be a null pointer constant.
+ } else {
+ return (e->isNullPointerConstant(C, Expr::NPC_ValueDependentIsNull)
+ ? IIK_okay : IIK_nonlocal);
+ }
+
+ return IIK_nonlocal;
+}
+
+/// Check whether the given expression is a valid operand for an
+/// indirect copy/restore.
+static void checkIndirectCopyRestoreSource(Sema &S, Expr *src) {
+ assert(src->isRValue());
+
+ InvalidICRKind iik = isInvalidICRSource(S.Context, src, false);
+ if (iik == IIK_okay) return;
+
+ S.Diag(src->getExprLoc(), diag::err_arc_nonlocal_writeback)
+ << ((unsigned) iik - 1) // shift index into diagnostic explanations
+ << src->getSourceRange();
+}
+
/// \brief Determine whether we have compatible array types for the
/// purposes of GNU by-copy array initialization.
static bool hasCompatibleArrayTypes(ASTContext &Context,
@@ -3144,6 +3308,53 @@ static bool hasCompatibleArrayTypes(ASTContext &Context,
return Source->isConstantArrayType() && Dest->isIncompleteArrayType();
}
+static bool tryObjCWritebackConversion(Sema &S,
+ InitializationSequence &Sequence,
+ const InitializedEntity &Entity,
+ Expr *Initializer) {
+ bool ArrayDecay = false;
+ QualType ArgType = Initializer->getType();
+ QualType ArgPointee;
+ if (const ArrayType *ArgArrayType = S.Context.getAsArrayType(ArgType)) {
+ ArrayDecay = true;
+ ArgPointee = ArgArrayType->getElementType();
+ ArgType = S.Context.getPointerType(ArgPointee);
+ }
+
+ // Handle write-back conversion.
+ QualType ConvertedArgType;
+ if (!S.isObjCWritebackConversion(ArgType, Entity.getType(),
+ ConvertedArgType))
+ return false;
+
+ // We should copy unless we're passing to an argument explicitly
+ // marked 'out'.
+ bool ShouldCopy = true;
+ if (ParmVarDecl *param = cast_or_null<ParmVarDecl>(Entity.getDecl()))
+ ShouldCopy = (param->getObjCDeclQualifier() != ParmVarDecl::OBJC_TQ_Out);
+
+ // Do we need an lvalue conversion?
+ if (ArrayDecay || Initializer->isGLValue()) {
+ ImplicitConversionSequence ICS;
+ ICS.setStandard();
+ ICS.Standard.setAsIdentityConversion();
+
+ QualType ResultType;
+ if (ArrayDecay) {
+ ICS.Standard.First = ICK_Array_To_Pointer;
+ ResultType = S.Context.getPointerType(ArgPointee);
+ } else {
+ ICS.Standard.First = ICK_Lvalue_To_Rvalue;
+ ResultType = Initializer->getType().getNonLValueExprType(S.Context);
+ }
+
+ Sequence.AddConversionSequenceStep(ICS, ResultType);
+ }
+
+ Sequence.AddPassByIndirectCopyRestoreStep(Entity.getType(), ShouldCopy);
+ return true;
+}
+
InitializationSequence::InitializationSequence(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
@@ -3255,12 +3466,28 @@ InitializationSequence::InitializationSequence(Sema &S,
return;
}
- // Handle initialization in C
+ // Determine whether we should consider writeback conversions for
+ // Objective-C ARC.
+ bool allowObjCWritebackConversion = S.getLangOptions().ObjCAutoRefCount &&
+ Entity.getKind() == InitializedEntity::EK_Parameter;
+
+ // We're at the end of the line for C: it's either a write-back conversion
+ // or it's a C assignment. There's no need to check anything else.
if (!S.getLangOptions().CPlusPlus) {
+ // If allowed, check whether this is an Objective-C writeback conversion.
+ if (allowObjCWritebackConversion &&
+ tryObjCWritebackConversion(S, *this, Entity, Initializer)) {
+ return;
+ }
+
+ // Handle initialization in C
AddCAssignmentStep(DestType);
+ MaybeProduceObjCObject(S, *this, Entity);
return;
}
+ assert(S.getLangOptions().CPlusPlus);
+
// - If the destination type is a (possibly cv-qualified) class type:
if (DestType->isRecordType()) {
// - If the initialization is direct-initialization, or if it is
@@ -3294,6 +3521,7 @@ InitializationSequence::InitializationSequence(Sema &S,
// type, conversion functions are considered.
if (!SourceType.isNull() && SourceType->isRecordType()) {
TryUserDefinedConversion(S, Entity, Kind, Initializer, *this);
+ MaybeProduceObjCObject(S, *this, Entity);
return;
}
@@ -3302,12 +3530,38 @@ InitializationSequence::InitializationSequence(Sema &S,
// conversions (Clause 4) will be used, if necessary, to convert the
// initializer expression to the cv-unqualified version of the
// destination type; no user-defined conversions are considered.
- if (S.TryImplicitConversion(*this, Entity, Initializer,
- /*SuppressUserConversions*/ true,
+
+ ImplicitConversionSequence ICS
+ = S.TryImplicitConversion(Initializer, Entity.getType(),
+ /*SuppressUserConversions*/true,
/*AllowExplicitConversions*/ false,
/*InOverloadResolution*/ false,
- /*CStyle=*/Kind.isCStyleOrFunctionalCast()))
- {
+ /*CStyle=*/Kind.isCStyleOrFunctionalCast(),
+ allowObjCWritebackConversion);
+
+ if (ICS.isStandard() &&
+ ICS.Standard.Second == ICK_Writeback_Conversion) {
+ // Objective-C ARC writeback conversion.
+
+ // We should copy unless we're passing to an argument explicitly
+ // marked 'out'.
+ bool ShouldCopy = true;
+ if (ParmVarDecl *Param = cast_or_null<ParmVarDecl>(Entity.getDecl()))
+ ShouldCopy = (Param->getObjCDeclQualifier() != ParmVarDecl::OBJC_TQ_Out);
+
+ // If there was an lvalue adjustment, add it as a separate conversion.
+ if (ICS.Standard.First == ICK_Array_To_Pointer ||
+ ICS.Standard.First == ICK_Lvalue_To_Rvalue) {
+ ImplicitConversionSequence LvalueICS;
+ LvalueICS.setStandard();
+ LvalueICS.Standard.setAsIdentityConversion();
+ LvalueICS.Standard.setAllToTypes(ICS.Standard.getToType(0));
+ LvalueICS.Standard.First = ICS.Standard.First;
+ AddConversionSequenceStep(LvalueICS, ICS.Standard.getToType(0));
+ }
+
+ AddPassByIndirectCopyRestoreStep(Entity.getType(), ShouldCopy);
+ } else if (ICS.isBad()) {
DeclAccessPair dap;
if (Initializer->getType() == Context.OverloadTy &&
!S.ResolveAddressOfOverloadedFunction(Initializer
@@ -3315,6 +3569,10 @@ InitializationSequence::InitializationSequence(Sema &S,
SetFailed(InitializationSequence::FK_AddressOfOverloadFailed);
else
SetFailed(InitializationSequence::FK_ConversionFailed);
+ } else {
+ AddConversionSequenceStep(ICS, Entity.getType());
+
+ MaybeProduceObjCObject(S, *this, Entity);
}
}
@@ -3560,7 +3818,7 @@ static ExprResult CopyObject(Sema &S,
<< (int)Entity.getKind() << CurInitExpr->getType()
<< CurInitExpr->getSourceRange();
S.Diag(Best->Function->getLocation(), diag::note_unavailable_here)
- << Best->Function->isDeleted();
+ << 1 << Best->Function->isDeleted();
return ExprError();
}
@@ -3633,6 +3891,11 @@ void InitializationSequence::PrintInitLocationNote(Sema &S,
}
}
+static bool isReferenceBinding(const InitializationSequence::Step &s) {
+ return s.Kind == InitializationSequence::SK_BindReference ||
+ s.Kind == InitializationSequence::SK_BindReferenceToTemporary;
+}
+
ExprResult
InitializationSequence::Perform(Sema &S,
const InitializedEntity &Entity,
@@ -3684,19 +3947,9 @@ InitializationSequence::Perform(Sema &S,
}
}
-
- if (Kind.getKind() == InitializationKind::IK_Copy || Kind.isExplicitCast())
- return ExprResult(Args.release()[0]);
-
- if (Args.size() == 0)
- return S.Owned((Expr *)0);
-
- unsigned NumArgs = Args.size();
- return S.Owned(new (S.Context) ParenListExpr(S.Context,
- SourceLocation(),
- (Expr **)Args.release(),
- NumArgs,
- SourceLocation()));
+ assert(Kind.getKind() == InitializationKind::IK_Copy ||
+ Kind.isExplicitCast());
+ return ExprResult(Args.release()[0]);
}
// No steps means no initialization.
@@ -3733,7 +3986,10 @@ InitializationSequence::Perform(Sema &S,
case SK_CAssignment:
case SK_StringInit:
case SK_ObjCObjectConversion:
- case SK_ArrayInit: {
+ case SK_ArrayInit:
+ case SK_PassByIndirectCopyRestore:
+ case SK_PassByIndirectRestore:
+ case SK_ProduceObjCObject: {
assert(Args.size() == 1);
CurInit = Args.get()[0];
if (!CurInit.get()) return ExprError();
@@ -3841,12 +4097,22 @@ InitializationSequence::Perform(Sema &S,
break;
case SK_BindReferenceToTemporary:
- // Reference binding does not have any corresponding ASTs.
-
// Check exception specifications
if (S.CheckExceptionSpecCompatibility(CurInit.get(), DestType))
return ExprError();
+ // Materialize the temporary into memory.
+ CurInit = new (S.Context) MaterializeTemporaryExpr(
+ Entity.getType().getNonReferenceType(),
+ CurInit.get(),
+ Entity.getType()->isLValueReferenceType());
+
+ // If we're binding to an Objective-C object that has lifetime, we
+ // need cleanups.
+ if (S.getLangOptions().ObjCAutoRefCount &&
+ CurInit.get()->getType()->isObjCLifetimeType())
+ S.ExprNeedsCleanups = true;
+
break;
case SK_ExtraneousCopyToTemporary:
@@ -3925,8 +4191,7 @@ InitializationSequence::Perform(Sema &S,
CreatedObject = Conversion->getResultType()->isRecordType();
}
- bool RequiresCopy = !IsCopy &&
- getKind() != InitializationSequence::ReferenceBinding;
+ bool RequiresCopy = !IsCopy && !isReferenceBinding(Steps.back());
if (RequiresCopy || shouldBindAsTemporary(Entity))
CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
else if (CreatedObject && shouldDestroyTemporary(Entity)) {
@@ -3969,10 +4234,14 @@ InitializationSequence::Perform(Sema &S,
}
case SK_ConversionSequence: {
+ Sema::CheckedConversionKind CCK
+ = Kind.isCStyleCast()? Sema::CCK_CStyleCast
+ : Kind.isFunctionalCast()? Sema::CCK_FunctionalCast
+ : Kind.isExplicitCast()? Sema::CCK_OtherCast
+ : Sema::CCK_ImplicitConversion;
ExprResult CurInitExprRes =
S.PerformImplicitConversion(CurInit.get(), Step->Type, *Step->ICS,
- getAssignmentAction(Entity),
- Kind.isCStyleOrFunctionalCast());
+ getAssignmentAction(Entity), CCK);
if (CurInitExprRes.isInvalid())
return ExprError();
CurInit = move(CurInitExprRes);
@@ -4182,7 +4451,20 @@ InitializationSequence::Perform(Sema &S,
}
}
}
+ break;
+ case SK_PassByIndirectCopyRestore:
+ case SK_PassByIndirectRestore:
+ checkIndirectCopyRestoreSource(S, CurInit.get());
+ CurInit = S.Owned(new (S.Context)
+ ObjCIndirectCopyRestoreExpr(CurInit.take(), Step->Type,
+ Step->Kind == SK_PassByIndirectCopyRestore));
+ break;
+
+ case SK_ProduceObjCObject:
+ CurInit = S.Owned(ImplicitCastExpr::Create(S.Context, Step->Type,
+ CK_ObjCProduceObject,
+ CurInit.take(), 0, VK_RValue));
break;
}
}
@@ -4278,7 +4560,7 @@ bool InitializationSequence::Diagnose(Sema &S,
true);
if (Ovl == OR_Deleted) {
S.Diag(Best->Function->getLocation(), diag::note_unavailable_here)
- << Best->Function->isDeleted();
+ << 1 << Best->Function->isDeleted();
} else {
llvm_unreachable("Inconsistent overload resolution?");
}
@@ -4443,7 +4725,7 @@ bool InitializationSequence::Diagnose(Sema &S,
= FailedCandidateSet.BestViableFunction(S, Kind.getLocation(), Best);
if (Ovl == OR_Deleted) {
S.Diag(Best->Function->getLocation(), diag::note_unavailable_here)
- << Best->Function->isDeleted();
+ << 1 << Best->Function->isDeleted();
} else {
llvm_unreachable("Inconsistent overload resolution?");
}
@@ -4587,10 +4869,6 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const {
case NormalSequence:
OS << "Normal sequence: ";
break;
-
- case ReferenceBinding:
- OS << "Reference binding: ";
- break;
}
for (step_iterator S = step_begin(), SEnd = step_end(); S != SEnd; ++S) {
@@ -4674,6 +4952,18 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const {
case SK_ArrayInit:
OS << "array initialization";
break;
+
+ case SK_PassByIndirectCopyRestore:
+ OS << "pass by indirect copy and restore";
+ break;
+
+ case SK_PassByIndirectRestore:
+ OS << "pass by indirect restore";
+ break;
+
+ case SK_ProduceObjCObject:
+ OS << "Objective-C object retension";
+ break;
}
}
}
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 92ade1efcf01..0e448e31207d 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -20,6 +20,7 @@
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/TemplateDeduction.h"
#include "clang/Sema/ExternalSemaSource.h"
+#include "clang/Sema/TypoCorrection.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Decl.h"
@@ -42,6 +43,7 @@
#include <iterator>
#include <utility>
#include <algorithm>
+#include <map>
using namespace clang;
using namespace sema;
@@ -207,6 +209,7 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind,
bool Redeclaration) {
unsigned IDNS = 0;
switch (NameKind) {
+ case Sema::LookupObjCImplicitSelfParam:
case Sema::LookupOrdinaryName:
case Sema::LookupRedeclarationWithLinkage:
IDNS = Decl::IDNS_Ordinary;
@@ -1095,7 +1098,10 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) {
if (LeftStartingScope && !((*I)->hasLinkage()))
continue;
}
-
+ else if (NameKind == LookupObjCImplicitSelfParam &&
+ !isa<ImplicitParamDecl>(*I))
+ continue;
+
R.addDecl(*I);
if ((*I)->getAttr<OverloadableAttr>()) {
@@ -1379,6 +1385,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
// Look for this member in our base classes
CXXRecordDecl::BaseMatchesCallback *BaseCallback = 0;
switch (R.getLookupKind()) {
+ case LookupObjCImplicitSelfParam:
case LookupOrdinaryName:
case LookupMemberName:
case LookupRedeclarationWithLinkage:
@@ -2137,15 +2144,15 @@ void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
}
}
-Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *D,
+Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
CXXSpecialMember SM,
bool ConstArg,
bool VolatileArg,
bool RValueThis,
bool ConstThis,
bool VolatileThis) {
- D = D->getDefinition();
- assert((D && !D->isBeingDefined()) &&
+ RD = RD->getDefinition();
+ assert((RD && !RD->isBeingDefined()) &&
"doing special member lookup into record that isn't fully complete");
if (RValueThis || ConstThis || VolatileThis)
assert((SM == CXXCopyAssignment || SM == CXXMoveAssignment) &&
@@ -2155,7 +2162,7 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *D,
"parameter-less special members can't have qualified arguments");
llvm::FoldingSetNodeID ID;
- ID.AddPointer(D);
+ ID.AddPointer(RD);
ID.AddInteger(SM);
ID.AddInteger(ConstArg);
ID.AddInteger(VolatileArg);
@@ -2176,9 +2183,9 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *D,
SpecialMemberCache.InsertNode(Result, InsertPoint);
if (SM == CXXDestructor) {
- if (!D->hasDeclaredDestructor())
- DeclareImplicitDestructor(D);
- CXXDestructorDecl *DD = D->getDestructor();
+ if (!RD->hasDeclaredDestructor())
+ DeclareImplicitDestructor(RD);
+ CXXDestructorDecl *DD = RD->getDestructor();
assert(DD && "record without a destructor");
Result->setMethod(DD);
Result->setSuccess(DD->isDeleted());
@@ -2188,7 +2195,7 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *D,
// Prepare for overload resolution. Here we construct a synthetic argument
// if necessary and make sure that implicit functions are declared.
- CanQualType CanTy = Context.getCanonicalType(Context.getTagDeclType(D));
+ CanQualType CanTy = Context.getCanonicalType(Context.getTagDeclType(RD));
DeclarationName Name;
Expr *Arg = 0;
unsigned NumArgs;
@@ -2196,18 +2203,18 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *D,
if (SM == CXXDefaultConstructor) {
Name = Context.DeclarationNames.getCXXConstructorName(CanTy);
NumArgs = 0;
- if (D->needsImplicitDefaultConstructor())
- DeclareImplicitDefaultConstructor(D);
+ if (RD->needsImplicitDefaultConstructor())
+ DeclareImplicitDefaultConstructor(RD);
} else {
if (SM == CXXCopyConstructor || SM == CXXMoveConstructor) {
Name = Context.DeclarationNames.getCXXConstructorName(CanTy);
- if (!D->hasDeclaredCopyConstructor())
- DeclareImplicitCopyConstructor(D);
+ if (!RD->hasDeclaredCopyConstructor())
+ DeclareImplicitCopyConstructor(RD);
// TODO: Move constructors
} else {
Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal);
- if (!D->hasDeclaredCopyAssignment())
- DeclareImplicitCopyAssignment(D);
+ if (!RD->hasDeclaredCopyAssignment())
+ DeclareImplicitCopyAssignment(RD);
// TODO: Move assignment
}
@@ -2225,7 +2232,7 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *D,
// there is no semantic difference for class types in this restricted
// case.
ExprValueKind VK;
- if (SM == CXXCopyAssignment || SM == CXXMoveAssignment)
+ if (SM == CXXCopyConstructor || SM == CXXCopyAssignment)
VK = VK_LValue;
else
VK = VK_RValue;
@@ -2240,7 +2247,7 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *D,
ThisTy.addConst();
if (VolatileThis)
ThisTy.addVolatile();
- Expr::Classification ObjectClassification =
+ Expr::Classification Classification =
(new (Context) OpaqueValueExpr(SourceLocation(), ThisTy,
RValueThis ? VK_RValue : VK_LValue))->
Classify(Context);
@@ -2252,16 +2259,33 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *D,
DeclContext::lookup_iterator I, E;
Result->setConstParamMatch(false);
- llvm::tie(I, E) = D->lookup(Name);
+ llvm::tie(I, E) = RD->lookup(Name);
assert((I != E) &&
"lookup for a constructor or assignment operator was empty");
for ( ; I != E; ++I) {
- if ((*I)->isInvalidDecl())
+ Decl *Cand = *I;
+
+ if (Cand->isInvalidDecl())
continue;
- if (CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(*I)) {
- AddOverloadCandidate(M, DeclAccessPair::make(M, AS_public), &Arg, NumArgs,
- OCS, true);
+ if (UsingShadowDecl *U = dyn_cast<UsingShadowDecl>(Cand)) {
+ // FIXME: [namespace.udecl]p15 says that we should only consider a
+ // using declaration here if it does not match a declaration in the
+ // derived class. We do not implement this correctly in other cases
+ // either.
+ Cand = U->getTargetDecl();
+
+ if (Cand->isInvalidDecl())
+ continue;
+ }
+
+ if (CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(Cand)) {
+ if (SM == CXXCopyAssignment || SM == CXXMoveAssignment)
+ AddMethodCandidate(M, DeclAccessPair::make(M, AS_public), RD, ThisTy,
+ Classification, &Arg, NumArgs, OCS, true);
+ else
+ AddOverloadCandidate(M, DeclAccessPair::make(M, AS_public), &Arg,
+ NumArgs, OCS, true);
// Here we're looking for a const parameter to speed up creation of
// implicit copy methods.
@@ -2269,13 +2293,21 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *D,
(SM == CXXCopyConstructor &&
cast<CXXConstructorDecl>(M)->isCopyConstructor())) {
QualType ArgType = M->getType()->getAs<FunctionProtoType>()->getArgType(0);
- if (ArgType->getPointeeType().isConstQualified())
+ if (!ArgType->isReferenceType() ||
+ ArgType->getPointeeType().isConstQualified())
Result->setConstParamMatch(true);
}
+ } else if (FunctionTemplateDecl *Tmpl =
+ dyn_cast<FunctionTemplateDecl>(Cand)) {
+ if (SM == CXXCopyAssignment || SM == CXXMoveAssignment)
+ AddMethodTemplateCandidate(Tmpl, DeclAccessPair::make(Tmpl, AS_public),
+ RD, 0, ThisTy, Classification, &Arg, NumArgs,
+ OCS, true);
+ else
+ AddTemplateOverloadCandidate(Tmpl, DeclAccessPair::make(Tmpl, AS_public),
+ 0, &Arg, NumArgs, OCS, true);
} else {
- FunctionTemplateDecl *Tmpl = cast<FunctionTemplateDecl>(*I);
- AddTemplateOverloadCandidate(Tmpl, DeclAccessPair::make(Tmpl, AS_public),
- 0, &Arg, NumArgs, OCS, true);
+ assert(isa<UsingDecl>(Cand) && "illegal Kind of operator = Decl");
}
}
@@ -2310,10 +2342,10 @@ CXXConstructorDecl *Sema::LookupDefaultConstructor(CXXRecordDecl *Class) {
return cast_or_null<CXXConstructorDecl>(Result->getMethod());
}
-/// \brief Look up the copy constructor for the given class.
-CXXConstructorDecl *Sema::LookupCopyConstructor(CXXRecordDecl *Class,
- unsigned Quals,
- bool *ConstParamMatch) {
+/// \brief Look up the copying constructor for the given class.
+CXXConstructorDecl *Sema::LookupCopyingConstructor(CXXRecordDecl *Class,
+ unsigned Quals,
+ bool *ConstParamMatch) {
assert(!(Quals & ~(Qualifiers::Const | Qualifiers::Volatile)) &&
"non-const, non-volatile qualifiers for copy ctor arg");
SpecialMemberOverloadResult *Result =
@@ -2341,6 +2373,27 @@ DeclContext::lookup_result Sema::LookupConstructors(CXXRecordDecl *Class) {
return Class->lookup(Name);
}
+/// \brief Look up the copying assignment operator for the given class.
+CXXMethodDecl *Sema::LookupCopyingAssignment(CXXRecordDecl *Class,
+ unsigned Quals, bool RValueThis,
+ unsigned ThisQuals,
+ bool *ConstParamMatch) {
+ assert(!(Quals & ~(Qualifiers::Const | Qualifiers::Volatile)) &&
+ "non-const, non-volatile qualifiers for copy assignment arg");
+ assert(!(ThisQuals & ~(Qualifiers::Const | Qualifiers::Volatile)) &&
+ "non-const, non-volatile qualifiers for copy assignment this");
+ SpecialMemberOverloadResult *Result =
+ LookupSpecialMember(Class, CXXCopyAssignment, Quals & Qualifiers::Const,
+ Quals & Qualifiers::Volatile, RValueThis,
+ ThisQuals & Qualifiers::Const,
+ ThisQuals & Qualifiers::Volatile);
+
+ if (ConstParamMatch)
+ *ConstParamMatch = Result->hasConstParamMatch();
+
+ return Result->getMethod();
+}
+
/// \brief Look for the destructor of the given class.
///
/// During semantic analysis, this routine should be used in lieu of
@@ -2995,6 +3048,12 @@ LabelDecl *Sema::LookupOrCreateLabel(IdentifierInfo *II, SourceLocation Loc,
//===----------------------------------------------------------------------===//
namespace {
+
+typedef llvm::StringMap<TypoCorrection, llvm::BumpPtrAllocator> TypoResultsMap;
+typedef std::map<unsigned, TypoResultsMap *> TypoEditDistanceMap;
+
+static const unsigned MaxTypoDistanceResultSets = 5;
+
class TypoCorrectionConsumer : public VisibleDeclConsumer {
/// \brief The name written that is a typo in the source.
llvm::StringRef Typo;
@@ -3002,33 +3061,55 @@ class TypoCorrectionConsumer : public VisibleDeclConsumer {
/// \brief The results found that have the smallest edit distance
/// found (so far) with the typo name.
///
- /// The boolean value indicates whether there is a keyword with this name.
- llvm::StringMap<bool, llvm::BumpPtrAllocator> BestResults;
+ /// The pointer value being set to the current DeclContext indicates
+ /// whether there is a keyword with this name.
+ TypoEditDistanceMap BestResults;
+
+ /// \brief The worst of the best N edit distances found so far.
+ unsigned MaxEditDistance;
- /// \brief The best edit distance found so far.
- unsigned BestEditDistance;
+ Sema &SemaRef;
public:
- explicit TypoCorrectionConsumer(IdentifierInfo *Typo)
+ explicit TypoCorrectionConsumer(Sema &SemaRef, IdentifierInfo *Typo)
: Typo(Typo->getName()),
- BestEditDistance((std::numeric_limits<unsigned>::max)()) { }
+ MaxEditDistance((std::numeric_limits<unsigned>::max)()),
+ SemaRef(SemaRef) { }
+ ~TypoCorrectionConsumer() {
+ for (TypoEditDistanceMap::iterator I = BestResults.begin(),
+ IEnd = BestResults.end();
+ I != IEnd;
+ ++I)
+ delete I->second;
+ }
+
virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, bool InBaseClass);
void FoundName(llvm::StringRef Name);
- void addKeywordResult(ASTContext &Context, llvm::StringRef Keyword);
-
- typedef llvm::StringMap<bool, llvm::BumpPtrAllocator>::iterator iterator;
- iterator begin() { return BestResults.begin(); }
- iterator end() { return BestResults.end(); }
- void erase(iterator I) { BestResults.erase(I); }
+ void addKeywordResult(llvm::StringRef Keyword);
+ void addName(llvm::StringRef Name, NamedDecl *ND, unsigned Distance,
+ NestedNameSpecifier *NNS=NULL);
+ void addCorrection(TypoCorrection Correction);
+
+ typedef TypoResultsMap::iterator result_iterator;
+ typedef TypoEditDistanceMap::iterator distance_iterator;
+ distance_iterator begin() { return BestResults.begin(); }
+ distance_iterator end() { return BestResults.end(); }
+ void erase(distance_iterator I) { BestResults.erase(I); }
unsigned size() const { return BestResults.size(); }
bool empty() const { return BestResults.empty(); }
- bool &operator[](llvm::StringRef Name) {
- return BestResults[Name];
+ TypoCorrection &operator[](llvm::StringRef Name) {
+ return (*BestResults.begin()->second)[Name];
+ }
+
+ unsigned getMaxEditDistance() const {
+ return MaxEditDistance;
}
- unsigned getBestEditDistance() const { return BestEditDistance; }
+ unsigned getBestEditDistance() {
+ return (BestResults.empty()) ? MaxEditDistance : BestResults.begin()->first;
+ }
};
}
@@ -3053,55 +3134,181 @@ void TypoCorrectionConsumer::FoundName(llvm::StringRef Name) {
// Use a simple length-based heuristic to determine the minimum possible
// edit distance. If the minimum isn't good enough, bail out early.
unsigned MinED = abs((int)Name.size() - (int)Typo.size());
- if (MinED > BestEditDistance || (MinED && Typo.size() / MinED < 3))
+ if (MinED > MaxEditDistance || (MinED && Typo.size() / MinED < 3))
return;
// Compute an upper bound on the allowable edit distance, so that the
// edit-distance algorithm can short-circuit.
unsigned UpperBound =
- std::min(unsigned((Typo.size() + 2) / 3), BestEditDistance);
+ std::min(unsigned((Typo.size() + 2) / 3), MaxEditDistance);
// Compute the edit distance between the typo and the name of this
// entity. If this edit distance is not worse than the best edit
// distance we've seen so far, add it to the list of results.
unsigned ED = Typo.edit_distance(Name, true, UpperBound);
- if (ED == 0)
- return;
- if (ED < BestEditDistance) {
- // This result is better than any we've seen before; clear out
- // the previous results.
- BestResults.clear();
- BestEditDistance = ED;
- } else if (ED > BestEditDistance) {
+ if (ED > MaxEditDistance) {
// This result is worse than the best results we've seen so far;
// ignore it.
return;
}
- // Add this name to the list of results. By not assigning a value, we
- // keep the current value if we've seen this name before (either as a
- // keyword or as a declaration), or get the default value (not a keyword)
- // if we haven't seen it before.
- (void)BestResults[Name];
+ addName(Name, NULL, ED);
}
-void TypoCorrectionConsumer::addKeywordResult(ASTContext &Context,
- llvm::StringRef Keyword) {
+void TypoCorrectionConsumer::addKeywordResult(llvm::StringRef Keyword) {
// Compute the edit distance between the typo and this keyword.
// If this edit distance is not worse than the best edit
// distance we've seen so far, add it to the list of results.
unsigned ED = Typo.edit_distance(Keyword);
- if (ED < BestEditDistance) {
- BestResults.clear();
- BestEditDistance = ED;
- } else if (ED > BestEditDistance) {
+ if (ED > MaxEditDistance) {
// This result is worse than the best results we've seen so far;
// ignore it.
return;
}
- BestResults[Keyword] = true;
+ addName(Keyword, TypoCorrection::KeywordDecl(), ED);
+}
+
+void TypoCorrectionConsumer::addName(llvm::StringRef Name,
+ NamedDecl *ND,
+ unsigned Distance,
+ NestedNameSpecifier *NNS) {
+ addCorrection(TypoCorrection(&SemaRef.Context.Idents.get(Name),
+ ND, NNS, Distance));
+}
+
+void TypoCorrectionConsumer::addCorrection(TypoCorrection Correction) {
+ llvm::StringRef Name = Correction.getCorrectionAsIdentifierInfo()->getName();
+ TypoResultsMap *& Map = BestResults[Correction.getEditDistance()];
+ if (!Map)
+ Map = new TypoResultsMap;
+
+ TypoCorrection &CurrentCorrection = (*Map)[Name];
+ if (!CurrentCorrection ||
+ // FIXME: The following should be rolled up into an operator< on
+ // TypoCorrection with a more principled definition.
+ CurrentCorrection.isKeyword() < Correction.isKeyword() ||
+ Correction.getAsString(SemaRef.getLangOptions()) <
+ CurrentCorrection.getAsString(SemaRef.getLangOptions()))
+ CurrentCorrection = Correction;
+
+ while (BestResults.size() > MaxTypoDistanceResultSets) {
+ TypoEditDistanceMap::iterator Last = BestResults.end();
+ --Last;
+ delete Last->second;
+ BestResults.erase(Last);
+ }
+}
+
+namespace {
+
+class SpecifierInfo {
+ public:
+ DeclContext* DeclCtx;
+ NestedNameSpecifier* NameSpecifier;
+ unsigned EditDistance;
+
+ SpecifierInfo(DeclContext *Ctx, NestedNameSpecifier *NNS, unsigned ED)
+ : DeclCtx(Ctx), NameSpecifier(NNS), EditDistance(ED) {}
+};
+
+typedef llvm::SmallVector<DeclContext*, 4> DeclContextList;
+typedef llvm::SmallVector<SpecifierInfo, 16> SpecifierInfoList;
+
+class NamespaceSpecifierSet {
+ ASTContext &Context;
+ DeclContextList CurContextChain;
+ bool isSorted;
+
+ SpecifierInfoList Specifiers;
+ llvm::SmallSetVector<unsigned, 4> Distances;
+ llvm::DenseMap<unsigned, SpecifierInfoList> DistanceMap;
+
+ /// \brief Helper for building the list of DeclContexts between the current
+ /// context and the top of the translation unit
+ static DeclContextList BuildContextChain(DeclContext *Start);
+
+ void SortNamespaces();
+
+ public:
+ explicit NamespaceSpecifierSet(ASTContext &Context, DeclContext *CurContext)
+ : Context(Context), CurContextChain(BuildContextChain(CurContext)),
+ isSorted(true) {}
+
+ /// \brief Add the namespace to the set, computing the corresponding
+ /// NestedNameSpecifier and its distance in the process.
+ void AddNamespace(NamespaceDecl *ND);
+
+ typedef SpecifierInfoList::iterator iterator;
+ iterator begin() {
+ if (!isSorted) SortNamespaces();
+ return Specifiers.begin();
+ }
+ iterator end() { return Specifiers.end(); }
+};
+
+}
+
+DeclContextList NamespaceSpecifierSet::BuildContextChain(DeclContext *Start) {
+ assert(Start && "Bulding a context chain from a null context");
+ DeclContextList Chain;
+ for (DeclContext *DC = Start->getPrimaryContext(); DC != NULL;
+ DC = DC->getLookupParent()) {
+ NamespaceDecl *ND = dyn_cast_or_null<NamespaceDecl>(DC);
+ if (!DC->isInlineNamespace() && !DC->isTransparentContext() &&
+ !(ND && ND->isAnonymousNamespace()))
+ Chain.push_back(DC->getPrimaryContext());
+ }
+ return Chain;
+}
+
+void NamespaceSpecifierSet::SortNamespaces() {
+ llvm::SmallVector<unsigned, 4> sortedDistances;
+ sortedDistances.append(Distances.begin(), Distances.end());
+
+ if (sortedDistances.size() > 1)
+ std::sort(sortedDistances.begin(), sortedDistances.end());
+
+ Specifiers.clear();
+ for (llvm::SmallVector<unsigned, 4>::iterator DI = sortedDistances.begin(),
+ DIEnd = sortedDistances.end();
+ DI != DIEnd; ++DI) {
+ SpecifierInfoList &SpecList = DistanceMap[*DI];
+ Specifiers.append(SpecList.begin(), SpecList.end());
+ }
+
+ isSorted = true;
+}
+
+void NamespaceSpecifierSet::AddNamespace(NamespaceDecl *ND) {
+ DeclContext *Ctx = cast<DeclContext>(ND);
+ NestedNameSpecifier *NNS = NULL;
+ unsigned NumSpecifiers = 0;
+ DeclContextList NamespaceDeclChain(BuildContextChain(Ctx));
+
+ // Eliminate common elements from the two DeclContext chains
+ for (DeclContextList::reverse_iterator C = CurContextChain.rbegin(),
+ CEnd = CurContextChain.rend();
+ C != CEnd && !NamespaceDeclChain.empty() &&
+ NamespaceDeclChain.back() == *C; ++C) {
+ NamespaceDeclChain.pop_back();
+ }
+
+ // Build the NestedNameSpecifier from what is left of the NamespaceDeclChain
+ for (DeclContextList::reverse_iterator C = NamespaceDeclChain.rbegin(),
+ CEnd = NamespaceDeclChain.rend();
+ C != CEnd; ++C) {
+ NamespaceDecl *ND = dyn_cast_or_null<NamespaceDecl>(*C);
+ if (ND) {
+ NNS = NestedNameSpecifier::Create(Context, NNS, ND);
+ ++NumSpecifiers;
+ }
+ }
+
+ isSorted = false;
+ Distances.insert(NumSpecifiers);
+ DistanceMap[NumSpecifiers].push_back(SpecifierInfo(Ctx, NNS, NumSpecifiers));
}
/// \brief Perform name lookup for a possible result for typo correction.
@@ -3155,14 +3362,193 @@ static void LookupPotentialTypoResult(Sema &SemaRef,
}
}
+/// \brief Add keywords to the consumer as possible typo corrections.
+static void AddKeywordsToConsumer(Sema &SemaRef,
+ TypoCorrectionConsumer &Consumer,
+ Scope *S, Sema::CorrectTypoContext CTC) {
+ // Add context-dependent keywords.
+ bool WantTypeSpecifiers = false;
+ bool WantExpressionKeywords = false;
+ bool WantCXXNamedCasts = false;
+ bool WantRemainingKeywords = false;
+ switch (CTC) {
+ case Sema::CTC_Unknown:
+ WantTypeSpecifiers = true;
+ WantExpressionKeywords = true;
+ WantCXXNamedCasts = true;
+ WantRemainingKeywords = true;
+
+ if (ObjCMethodDecl *Method = SemaRef.getCurMethodDecl())
+ if (Method->getClassInterface() &&
+ Method->getClassInterface()->getSuperClass())
+ Consumer.addKeywordResult("super");
+
+ break;
+
+ case Sema::CTC_NoKeywords:
+ break;
+
+ case Sema::CTC_Type:
+ WantTypeSpecifiers = true;
+ break;
+
+ case Sema::CTC_ObjCMessageReceiver:
+ Consumer.addKeywordResult("super");
+ // Fall through to handle message receivers like expressions.
+
+ case Sema::CTC_Expression:
+ if (SemaRef.getLangOptions().CPlusPlus)
+ WantTypeSpecifiers = true;
+ WantExpressionKeywords = true;
+ // Fall through to get C++ named casts.
+
+ case Sema::CTC_CXXCasts:
+ WantCXXNamedCasts = true;
+ break;
+
+ case Sema::CTC_ObjCPropertyLookup:
+ // FIXME: Add "isa"?
+ break;
+
+ case Sema::CTC_MemberLookup:
+ if (SemaRef.getLangOptions().CPlusPlus)
+ Consumer.addKeywordResult("template");
+ break;
+
+ case Sema::CTC_ObjCIvarLookup:
+ break;
+ }
+
+ if (WantTypeSpecifiers) {
+ // Add type-specifier keywords to the set of results.
+ const char *CTypeSpecs[] = {
+ "char", "const", "double", "enum", "float", "int", "long", "short",
+ "signed", "struct", "union", "unsigned", "void", "volatile",
+ "_Complex", "_Imaginary",
+ // storage-specifiers as well
+ "extern", "inline", "static", "typedef"
+ };
+
+ const unsigned NumCTypeSpecs = sizeof(CTypeSpecs) / sizeof(CTypeSpecs[0]);
+ for (unsigned I = 0; I != NumCTypeSpecs; ++I)
+ Consumer.addKeywordResult(CTypeSpecs[I]);
+
+ if (SemaRef.getLangOptions().C99)
+ Consumer.addKeywordResult("restrict");
+ if (SemaRef.getLangOptions().Bool || SemaRef.getLangOptions().CPlusPlus)
+ Consumer.addKeywordResult("bool");
+ else if (SemaRef.getLangOptions().C99)
+ Consumer.addKeywordResult("_Bool");
+
+ if (SemaRef.getLangOptions().CPlusPlus) {
+ Consumer.addKeywordResult("class");
+ Consumer.addKeywordResult("typename");
+ Consumer.addKeywordResult("wchar_t");
+
+ if (SemaRef.getLangOptions().CPlusPlus0x) {
+ Consumer.addKeywordResult("char16_t");
+ Consumer.addKeywordResult("char32_t");
+ Consumer.addKeywordResult("constexpr");
+ Consumer.addKeywordResult("decltype");
+ Consumer.addKeywordResult("thread_local");
+ }
+ }
+
+ if (SemaRef.getLangOptions().GNUMode)
+ Consumer.addKeywordResult("typeof");
+ }
+
+ if (WantCXXNamedCasts && SemaRef.getLangOptions().CPlusPlus) {
+ Consumer.addKeywordResult("const_cast");
+ Consumer.addKeywordResult("dynamic_cast");
+ Consumer.addKeywordResult("reinterpret_cast");
+ Consumer.addKeywordResult("static_cast");
+ }
+
+ if (WantExpressionKeywords) {
+ Consumer.addKeywordResult("sizeof");
+ if (SemaRef.getLangOptions().Bool || SemaRef.getLangOptions().CPlusPlus) {
+ Consumer.addKeywordResult("false");
+ Consumer.addKeywordResult("true");
+ }
+
+ if (SemaRef.getLangOptions().CPlusPlus) {
+ const char *CXXExprs[] = {
+ "delete", "new", "operator", "throw", "typeid"
+ };
+ const unsigned NumCXXExprs = sizeof(CXXExprs) / sizeof(CXXExprs[0]);
+ for (unsigned I = 0; I != NumCXXExprs; ++I)
+ Consumer.addKeywordResult(CXXExprs[I]);
+
+ if (isa<CXXMethodDecl>(SemaRef.CurContext) &&
+ cast<CXXMethodDecl>(SemaRef.CurContext)->isInstance())
+ Consumer.addKeywordResult("this");
+
+ if (SemaRef.getLangOptions().CPlusPlus0x) {
+ Consumer.addKeywordResult("alignof");
+ Consumer.addKeywordResult("nullptr");
+ }
+ }
+ }
+
+ if (WantRemainingKeywords) {
+ if (SemaRef.getCurFunctionOrMethodDecl() || SemaRef.getCurBlock()) {
+ // Statements.
+ const char *CStmts[] = {
+ "do", "else", "for", "goto", "if", "return", "switch", "while" };
+ const unsigned NumCStmts = sizeof(CStmts) / sizeof(CStmts[0]);
+ for (unsigned I = 0; I != NumCStmts; ++I)
+ Consumer.addKeywordResult(CStmts[I]);
+
+ if (SemaRef.getLangOptions().CPlusPlus) {
+ Consumer.addKeywordResult("catch");
+ Consumer.addKeywordResult("try");
+ }
+
+ if (S && S->getBreakParent())
+ Consumer.addKeywordResult("break");
+
+ if (S && S->getContinueParent())
+ Consumer.addKeywordResult("continue");
+
+ if (!SemaRef.getCurFunction()->SwitchStack.empty()) {
+ Consumer.addKeywordResult("case");
+ Consumer.addKeywordResult("default");
+ }
+ } else {
+ if (SemaRef.getLangOptions().CPlusPlus) {
+ Consumer.addKeywordResult("namespace");
+ Consumer.addKeywordResult("template");
+ }
+
+ if (S && S->isClassScope()) {
+ Consumer.addKeywordResult("explicit");
+ Consumer.addKeywordResult("friend");
+ Consumer.addKeywordResult("mutable");
+ Consumer.addKeywordResult("private");
+ Consumer.addKeywordResult("protected");
+ Consumer.addKeywordResult("public");
+ Consumer.addKeywordResult("virtual");
+ }
+ }
+
+ if (SemaRef.getLangOptions().CPlusPlus) {
+ Consumer.addKeywordResult("using");
+
+ if (SemaRef.getLangOptions().CPlusPlus0x)
+ Consumer.addKeywordResult("static_assert");
+ }
+ }
+}
+
/// \brief Try to "correct" a typo in the source code by finding
/// visible declarations whose names are similar to the name that was
/// present in the source code.
///
-/// \param Res the \c LookupResult structure that contains the name
-/// that was present in the source code along with the name-lookup
-/// criteria used to search for the name. On success, this structure
-/// will contain the results of name lookup.
+/// \param TypoName the \c DeclarationNameInfo structure that contains
+/// the name that was present in the source code along with its location.
+///
+/// \param LookupKind the name-lookup criteria used to search for the name.
///
/// \param S the scope in which name lookup occurs.
///
@@ -3181,60 +3567,64 @@ static void LookupPotentialTypoResult(Sema &SemaRef,
/// \param OPT when non-NULL, the search for visible declarations will
/// also walk the protocols in the qualified interfaces of \p OPT.
///
-/// \returns the corrected name if the typo was corrected, otherwise returns an
-/// empty \c DeclarationName. When a typo was corrected, the result structure
-/// may contain the results of name lookup for the correct name or it may be
-/// empty.
-DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS,
- DeclContext *MemberContext,
- bool EnteringContext,
- CorrectTypoContext CTC,
- const ObjCObjectPointerType *OPT) {
+/// \returns a \c TypoCorrection containing the corrected name if the typo
+/// along with information such as the \c NamedDecl where the corrected name
+/// was declared, and any additional \c NestedNameSpecifier needed to access
+/// it (C++ only). The \c TypoCorrection is empty if there is no correction.
+TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
+ Sema::LookupNameKind LookupKind,
+ Scope *S, CXXScopeSpec *SS,
+ DeclContext *MemberContext,
+ bool EnteringContext,
+ CorrectTypoContext CTC,
+ const ObjCObjectPointerType *OPT) {
if (Diags.hasFatalErrorOccurred() || !getLangOptions().SpellChecking)
- return DeclarationName();
+ return TypoCorrection();
// We only attempt to correct typos for identifiers.
- IdentifierInfo *Typo = Res.getLookupName().getAsIdentifierInfo();
+ IdentifierInfo *Typo = TypoName.getName().getAsIdentifierInfo();
if (!Typo)
- return DeclarationName();
+ return TypoCorrection();
// If the scope specifier itself was invalid, don't try to correct
// typos.
if (SS && SS->isInvalid())
- return DeclarationName();
+ return TypoCorrection();
// Never try to correct typos during template deduction or
// instantiation.
if (!ActiveTemplateInstantiations.empty())
- return DeclarationName();
+ return TypoCorrection();
- TypoCorrectionConsumer Consumer(Typo);
+ NamespaceSpecifierSet Namespaces(Context, CurContext);
+
+ TypoCorrectionConsumer Consumer(*this, Typo);
// Perform name lookup to find visible, similarly-named entities.
bool IsUnqualifiedLookup = false;
if (MemberContext) {
- LookupVisibleDecls(MemberContext, Res.getLookupKind(), Consumer);
+ LookupVisibleDecls(MemberContext, LookupKind, Consumer);
// Look in qualified interfaces.
if (OPT) {
for (ObjCObjectPointerType::qual_iterator
I = OPT->qual_begin(), E = OPT->qual_end();
I != E; ++I)
- LookupVisibleDecls(*I, Res.getLookupKind(), Consumer);
+ LookupVisibleDecls(*I, LookupKind, Consumer);
}
} else if (SS && SS->isSet()) {
DeclContext *DC = computeDeclContext(*SS, EnteringContext);
if (!DC)
- return DeclarationName();
+ return TypoCorrection();
// Provide a stop gap for files that are just seriously broken. Trying
// to correct all typos can turn into a HUGE performance penalty, causing
// some files to take minutes to get rejected by the parser.
if (TyposCorrected + UnqualifiedTyposCorrected.size() >= 20)
- return DeclarationName();
+ return TypoCorrection();
++TyposCorrected;
- LookupVisibleDecls(DC, Res.getLookupKind(), Consumer);
+ LookupVisibleDecls(DC, LookupKind, Consumer);
} else {
IsUnqualifiedLookup = true;
UnqualifiedTyposCorrectedMap::iterator Cached
@@ -3244,7 +3634,7 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS,
// to correct all typos can turn into a HUGE performance penalty, causing
// some files to take minutes to get rejected by the parser.
if (TyposCorrected + UnqualifiedTyposCorrected.size() >= 20)
- return DeclarationName();
+ return TypoCorrection();
// For unqualified lookup, look through all of the names that we have
// seen in this translation unit.
@@ -3268,313 +3658,225 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS,
} else {
// Use the cached value, unless it's a keyword. In the keyword case, we'll
// end up adding the keyword below.
- if (Cached->second.first.empty())
- return DeclarationName();
+ if (!Cached->second)
+ return TypoCorrection();
- if (!Cached->second.second)
- Consumer.FoundName(Cached->second.first);
+ if (!Cached->second.isKeyword())
+ Consumer.addCorrection(Cached->second);
}
}
- // Add context-dependent keywords.
- bool WantTypeSpecifiers = false;
- bool WantExpressionKeywords = false;
- bool WantCXXNamedCasts = false;
- bool WantRemainingKeywords = false;
- switch (CTC) {
- case CTC_Unknown:
- WantTypeSpecifiers = true;
- WantExpressionKeywords = true;
- WantCXXNamedCasts = true;
- WantRemainingKeywords = true;
-
- if (ObjCMethodDecl *Method = getCurMethodDecl())
- if (Method->getClassInterface() &&
- Method->getClassInterface()->getSuperClass())
- Consumer.addKeywordResult(Context, "super");
-
- break;
-
- case CTC_NoKeywords:
- break;
-
- case CTC_Type:
- WantTypeSpecifiers = true;
- break;
-
- case CTC_ObjCMessageReceiver:
- Consumer.addKeywordResult(Context, "super");
- // Fall through to handle message receivers like expressions.
-
- case CTC_Expression:
- if (getLangOptions().CPlusPlus)
- WantTypeSpecifiers = true;
- WantExpressionKeywords = true;
- // Fall through to get C++ named casts.
-
- case CTC_CXXCasts:
- WantCXXNamedCasts = true;
- break;
-
- case CTC_ObjCPropertyLookup:
- // FIXME: Add "isa"?
- break;
+ AddKeywordsToConsumer(*this, Consumer, S, CTC);
- case CTC_MemberLookup:
- if (getLangOptions().CPlusPlus)
- Consumer.addKeywordResult(Context, "template");
- break;
+ // If we haven't found anything, we're done.
+ if (Consumer.empty()) {
+ // If this was an unqualified lookup, note that no correction was found.
+ if (IsUnqualifiedLookup)
+ (void)UnqualifiedTyposCorrected[Typo];
- case CTC_ObjCIvarLookup:
- break;
+ return TypoCorrection();
}
- if (WantTypeSpecifiers) {
- // Add type-specifier keywords to the set of results.
- const char *CTypeSpecs[] = {
- "char", "const", "double", "enum", "float", "int", "long", "short",
- "signed", "struct", "union", "unsigned", "void", "volatile", "_Bool",
- "_Complex", "_Imaginary",
- // storage-specifiers as well
- "extern", "inline", "static", "typedef"
- };
-
- const unsigned NumCTypeSpecs = sizeof(CTypeSpecs) / sizeof(CTypeSpecs[0]);
- for (unsigned I = 0; I != NumCTypeSpecs; ++I)
- Consumer.addKeywordResult(Context, CTypeSpecs[I]);
-
- if (getLangOptions().C99)
- Consumer.addKeywordResult(Context, "restrict");
- if (getLangOptions().Bool || getLangOptions().CPlusPlus)
- Consumer.addKeywordResult(Context, "bool");
-
- if (getLangOptions().CPlusPlus) {
- Consumer.addKeywordResult(Context, "class");
- Consumer.addKeywordResult(Context, "typename");
- Consumer.addKeywordResult(Context, "wchar_t");
-
- if (getLangOptions().CPlusPlus0x) {
- Consumer.addKeywordResult(Context, "char16_t");
- Consumer.addKeywordResult(Context, "char32_t");
- Consumer.addKeywordResult(Context, "constexpr");
- Consumer.addKeywordResult(Context, "decltype");
- Consumer.addKeywordResult(Context, "thread_local");
- }
- }
+ // Make sure that the user typed at least 3 characters for each correction
+ // made. Otherwise, we don't even both looking at the results.
+ unsigned ED = Consumer.getBestEditDistance();
+ if (ED > 0 && Typo->getName().size() / ED < 3) {
+ // If this was an unqualified lookup, note that no correction was found.
+ if (IsUnqualifiedLookup)
+ (void)UnqualifiedTyposCorrected[Typo];
- if (getLangOptions().GNUMode)
- Consumer.addKeywordResult(Context, "typeof");
+ return TypoCorrection();
}
- if (WantCXXNamedCasts && getLangOptions().CPlusPlus) {
- Consumer.addKeywordResult(Context, "const_cast");
- Consumer.addKeywordResult(Context, "dynamic_cast");
- Consumer.addKeywordResult(Context, "reinterpret_cast");
- Consumer.addKeywordResult(Context, "static_cast");
+ // Build the NestedNameSpecifiers for the KnownNamespaces
+ if (getLangOptions().CPlusPlus) {
+ // Load any externally-known namespaces.
+ if (ExternalSource && !LoadedExternalKnownNamespaces) {
+ llvm::SmallVector<NamespaceDecl *, 4> ExternalKnownNamespaces;
+ LoadedExternalKnownNamespaces = true;
+ ExternalSource->ReadKnownNamespaces(ExternalKnownNamespaces);
+ for (unsigned I = 0, N = ExternalKnownNamespaces.size(); I != N; ++I)
+ KnownNamespaces[ExternalKnownNamespaces[I]] = true;
+ }
+
+ for (llvm::DenseMap<NamespaceDecl*, bool>::iterator
+ KNI = KnownNamespaces.begin(),
+ KNIEnd = KnownNamespaces.end();
+ KNI != KNIEnd; ++KNI)
+ Namespaces.AddNamespace(KNI->first);
}
- if (WantExpressionKeywords) {
- Consumer.addKeywordResult(Context, "sizeof");
- if (getLangOptions().Bool || getLangOptions().CPlusPlus) {
- Consumer.addKeywordResult(Context, "false");
- Consumer.addKeywordResult(Context, "true");
- }
+ // Weed out any names that could not be found by name lookup.
+ llvm::SmallPtrSet<IdentifierInfo*, 16> QualifiedResults;
+ LookupResult TmpRes(*this, TypoName, LookupKind);
+ TmpRes.suppressDiagnostics();
+ while (!Consumer.empty()) {
+ TypoCorrectionConsumer::distance_iterator DI = Consumer.begin();
+ unsigned ED = DI->first;
+ for (TypoCorrectionConsumer::result_iterator I = DI->second->begin(),
+ IEnd = DI->second->end();
+ I != IEnd; /* Increment in loop. */) {
+ // If the item already has been looked up or is a keyword, keep it
+ if (I->second.isResolved()) {
+ ++I;
+ continue;
+ }
- if (getLangOptions().CPlusPlus) {
- const char *CXXExprs[] = {
- "delete", "new", "operator", "throw", "typeid"
- };
- const unsigned NumCXXExprs = sizeof(CXXExprs) / sizeof(CXXExprs[0]);
- for (unsigned I = 0; I != NumCXXExprs; ++I)
- Consumer.addKeywordResult(Context, CXXExprs[I]);
+ // Perform name lookup on this name.
+ IdentifierInfo *Name = I->second.getCorrectionAsIdentifierInfo();
+ LookupPotentialTypoResult(*this, TmpRes, Name, S, SS, MemberContext,
+ EnteringContext, CTC);
- if (isa<CXXMethodDecl>(CurContext) &&
- cast<CXXMethodDecl>(CurContext)->isInstance())
- Consumer.addKeywordResult(Context, "this");
+ switch (TmpRes.getResultKind()) {
+ case LookupResult::NotFound:
+ case LookupResult::NotFoundInCurrentInstantiation:
+ QualifiedResults.insert(Name);
+ // We didn't find this name in our scope, or didn't like what we found;
+ // ignore it.
+ {
+ TypoCorrectionConsumer::result_iterator Next = I;
+ ++Next;
+ DI->second->erase(I);
+ I = Next;
+ }
+ break;
- if (getLangOptions().CPlusPlus0x) {
- Consumer.addKeywordResult(Context, "alignof");
- Consumer.addKeywordResult(Context, "nullptr");
+ case LookupResult::Ambiguous:
+ // We don't deal with ambiguities.
+ return TypoCorrection();
+
+ case LookupResult::Found:
+ case LookupResult::FoundOverloaded:
+ case LookupResult::FoundUnresolvedValue:
+ I->second.setCorrectionDecl(TmpRes.getAsSingle<NamedDecl>());
+ // FIXME: This sets the CorrectionDecl to NULL for overloaded functions.
+ // It would be nice to find the right one with overload resolution.
+ ++I;
+ break;
}
}
- }
-
- if (WantRemainingKeywords) {
- if (getCurFunctionOrMethodDecl() || getCurBlock()) {
- // Statements.
- const char *CStmts[] = {
- "do", "else", "for", "goto", "if", "return", "switch", "while" };
- const unsigned NumCStmts = sizeof(CStmts) / sizeof(CStmts[0]);
- for (unsigned I = 0; I != NumCStmts; ++I)
- Consumer.addKeywordResult(Context, CStmts[I]);
-
- if (getLangOptions().CPlusPlus) {
- Consumer.addKeywordResult(Context, "catch");
- Consumer.addKeywordResult(Context, "try");
- }
- if (S && S->getBreakParent())
- Consumer.addKeywordResult(Context, "break");
-
- if (S && S->getContinueParent())
- Consumer.addKeywordResult(Context, "continue");
-
- if (!getCurFunction()->SwitchStack.empty()) {
- Consumer.addKeywordResult(Context, "case");
- Consumer.addKeywordResult(Context, "default");
- }
- } else {
- if (getLangOptions().CPlusPlus) {
- Consumer.addKeywordResult(Context, "namespace");
- Consumer.addKeywordResult(Context, "template");
- }
+ if (DI->second->empty())
+ Consumer.erase(DI);
+ else if (!getLangOptions().CPlusPlus || QualifiedResults.empty() || !ED)
+ // If there are results in the closest possible bucket, stop
+ break;
- if (S && S->isClassScope()) {
- Consumer.addKeywordResult(Context, "explicit");
- Consumer.addKeywordResult(Context, "friend");
- Consumer.addKeywordResult(Context, "mutable");
- Consumer.addKeywordResult(Context, "private");
- Consumer.addKeywordResult(Context, "protected");
- Consumer.addKeywordResult(Context, "public");
- Consumer.addKeywordResult(Context, "virtual");
+ // Only perform the qualified lookups for C++
+ if (getLangOptions().CPlusPlus) {
+ TmpRes.suppressDiagnostics();
+ for (llvm::SmallPtrSet<IdentifierInfo*,
+ 16>::iterator QRI = QualifiedResults.begin(),
+ QRIEnd = QualifiedResults.end();
+ QRI != QRIEnd; ++QRI) {
+ for (NamespaceSpecifierSet::iterator NI = Namespaces.begin(),
+ NIEnd = Namespaces.end();
+ NI != NIEnd; ++NI) {
+ DeclContext *Ctx = NI->DeclCtx;
+ unsigned QualifiedED = ED + NI->EditDistance;
+
+ // Stop searching once the namespaces are too far away to create
+ // acceptable corrections for this identifier (since the namespaces
+ // are sorted in ascending order by edit distance)
+ if (QualifiedED > Consumer.getMaxEditDistance()) break;
+
+ TmpRes.clear();
+ TmpRes.setLookupName(*QRI);
+ if (!LookupQualifiedName(TmpRes, Ctx)) continue;
+
+ switch (TmpRes.getResultKind()) {
+ case LookupResult::Found:
+ case LookupResult::FoundOverloaded:
+ case LookupResult::FoundUnresolvedValue:
+ Consumer.addName((*QRI)->getName(), TmpRes.getAsSingle<NamedDecl>(),
+ QualifiedED, NI->NameSpecifier);
+ break;
+ case LookupResult::NotFound:
+ case LookupResult::NotFoundInCurrentInstantiation:
+ case LookupResult::Ambiguous:
+ break;
+ }
+ }
}
}
- if (getLangOptions().CPlusPlus) {
- Consumer.addKeywordResult(Context, "using");
-
- if (getLangOptions().CPlusPlus0x)
- Consumer.addKeywordResult(Context, "static_assert");
- }
+ QualifiedResults.clear();
}
- // If we haven't found anything, we're done.
- if (Consumer.empty()) {
- // If this was an unqualified lookup, note that no correction was found.
- if (IsUnqualifiedLookup)
- (void)UnqualifiedTyposCorrected[Typo];
+ // No corrections remain...
+ if (Consumer.empty()) return TypoCorrection();
- return DeclarationName();
- }
+ TypoResultsMap &BestResults = *Consumer.begin()->second;
+ ED = Consumer.begin()->first;
- // Make sure that the user typed at least 3 characters for each correction
- // made. Otherwise, we don't even both looking at the results.
-
- // We also suppress exact matches; those should be handled by a
- // different mechanism (e.g., one that introduces qualification in
- // C++).
- unsigned ED = Consumer.getBestEditDistance();
if (ED > 0 && Typo->getName().size() / ED < 3) {
// If this was an unqualified lookup, note that no correction was found.
if (IsUnqualifiedLookup)
(void)UnqualifiedTyposCorrected[Typo];
- return DeclarationName();
+ return TypoCorrection();
}
- // Weed out any names that could not be found by name lookup.
- bool LastLookupWasAccepted = false;
- for (TypoCorrectionConsumer::iterator I = Consumer.begin(),
- IEnd = Consumer.end();
- I != IEnd; /* Increment in loop. */) {
- // Keywords are always found.
- if (I->second) {
- ++I;
- continue;
- }
-
- // Perform name lookup on this name.
- IdentifierInfo *Name = &Context.Idents.get(I->getKey());
- LookupPotentialTypoResult(*this, Res, Name, S, SS, MemberContext,
- EnteringContext, CTC);
-
- switch (Res.getResultKind()) {
- case LookupResult::NotFound:
- case LookupResult::NotFoundInCurrentInstantiation:
- case LookupResult::Ambiguous:
- // We didn't find this name in our scope, or didn't like what we found;
- // ignore it.
- Res.suppressDiagnostics();
- {
- TypoCorrectionConsumer::iterator Next = I;
- ++Next;
- Consumer.erase(I);
- I = Next;
- }
- LastLookupWasAccepted = false;
- break;
-
- case LookupResult::Found:
- case LookupResult::FoundOverloaded:
- case LookupResult::FoundUnresolvedValue:
- ++I;
- LastLookupWasAccepted = true;
- break;
- }
-
- if (Res.isAmbiguous()) {
- // We don't deal with ambiguities.
- Res.suppressDiagnostics();
- Res.clear();
- return DeclarationName();
+ // If we have multiple possible corrections, eliminate the ones where we
+ // added namespace qualifiers to try to resolve the ambiguity (and to favor
+ // corrections without additional namespace qualifiers)
+ if (getLangOptions().CPlusPlus && BestResults.size() > 1) {
+ TypoCorrectionConsumer::distance_iterator DI = Consumer.begin();
+ for (TypoCorrectionConsumer::result_iterator I = DI->second->begin(),
+ IEnd = DI->second->end();
+ I != IEnd; /* Increment in loop. */) {
+ if (I->second.getCorrectionSpecifier() != NULL) {
+ TypoCorrectionConsumer::result_iterator Cur = I;
+ ++I;
+ DI->second->erase(Cur);
+ } else ++I;
}
}
// If only a single name remains, return that result.
- if (Consumer.size() == 1) {
- IdentifierInfo *Name = &Context.Idents.get(Consumer.begin()->getKey());
- if (Consumer.begin()->second) {
- Res.suppressDiagnostics();
- Res.clear();
-
- // Don't correct to a keyword that's the same as the typo; the keyword
- // wasn't actually in scope.
- if (ED == 0) {
- Res.setLookupName(Typo);
- return DeclarationName();
- }
+ if (BestResults.size() == 1) {
+ const llvm::StringMapEntry<TypoCorrection> &Correction = *(BestResults.begin());
+ const TypoCorrection &Result = Correction.second;
- } else if (!LastLookupWasAccepted) {
- // Perform name lookup on this name.
- LookupPotentialTypoResult(*this, Res, Name, S, SS, MemberContext,
- EnteringContext, CTC);
- }
+ // Don't correct to a keyword that's the same as the typo; the keyword
+ // wasn't actually in scope.
+ if (ED == 0 && Result.isKeyword()) return TypoCorrection();
// Record the correction for unqualified lookup.
if (IsUnqualifiedLookup)
- UnqualifiedTyposCorrected[Typo]
- = std::make_pair(Name->getName(), Consumer.begin()->second);
+ UnqualifiedTyposCorrected[Typo] = Result;
- return &Context.Idents.get(Consumer.begin()->getKey());
+ return Result;
}
- else if (Consumer.size() > 1 && CTC == CTC_ObjCMessageReceiver
- && Consumer["super"]) {
- // Prefix 'super' when we're completing in a message-receiver
+ else if (BestResults.size() > 1 && CTC == CTC_ObjCMessageReceiver
+ && BestResults["super"].isKeyword()) {
+ // Prefer 'super' when we're completing in a message-receiver
// context.
- Res.suppressDiagnostics();
- Res.clear();
// Don't correct to a keyword that's the same as the typo; the keyword
// wasn't actually in scope.
- if (ED == 0) {
- Res.setLookupName(Typo);
- return DeclarationName();
- }
+ if (ED == 0) return TypoCorrection();
// Record the correction for unqualified lookup.
if (IsUnqualifiedLookup)
- UnqualifiedTyposCorrected[Typo]
- = std::make_pair("super", Consumer.begin()->second);
+ UnqualifiedTyposCorrected[Typo] = BestResults["super"];
- return &Context.Idents.get("super");
+ return BestResults["super"];
}
- Res.suppressDiagnostics();
- Res.setLookupName(Typo);
- Res.clear();
- // Record the correction for unqualified lookup.
if (IsUnqualifiedLookup)
(void)UnqualifiedTyposCorrected[Typo];
- return DeclarationName();
+ return TypoCorrection();
+}
+
+std::string TypoCorrection::getAsString(const LangOptions &LO) const {
+ if (CorrectionNameSpec) {
+ std::string tmpBuffer;
+ llvm::raw_string_ostream PrefixOStream(tmpBuffer);
+ CorrectionNameSpec->print(PrefixOStream, PrintingPolicy(LO));
+ return PrefixOStream.str() + CorrectionName.getAsString();
+ }
+
+ return CorrectionName.getAsString();
}
diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp
index 6c4469cef9ef..d826ea8d84a4 100644
--- a/lib/Sema/SemaObjCProperty.cpp
+++ b/lib/Sema/SemaObjCProperty.cpp
@@ -24,6 +24,51 @@ using namespace clang;
// Grammar actions.
//===----------------------------------------------------------------------===//
+/// Check the internal consistency of a property declaration.
+static void checkARCPropertyDecl(Sema &S, ObjCPropertyDecl *property) {
+ if (property->isInvalidDecl()) return;
+
+ ObjCPropertyDecl::PropertyAttributeKind propertyKind
+ = property->getPropertyAttributes();
+ Qualifiers::ObjCLifetime propertyLifetime
+ = property->getType().getObjCLifetime();
+
+ // Nothing to do if we don't have a lifetime.
+ if (propertyLifetime == Qualifiers::OCL_None) return;
+
+ Qualifiers::ObjCLifetime expectedLifetime;
+ unsigned selector;
+
+ // Strong properties should have either strong or no lifetime.
+ if (propertyKind & (ObjCPropertyDecl::OBJC_PR_retain |
+ ObjCPropertyDecl::OBJC_PR_strong |
+ ObjCPropertyDecl::OBJC_PR_copy)) {
+ expectedLifetime = Qualifiers::OCL_Strong;
+ selector = 0;
+ } else if (propertyKind & ObjCPropertyDecl::OBJC_PR_weak) {
+ expectedLifetime = Qualifiers::OCL_Weak;
+ selector = 1;
+ } else if (propertyKind & (ObjCPropertyDecl::OBJC_PR_assign |
+ ObjCPropertyDecl::OBJC_PR_unsafe_unretained) &&
+ property->getType()->isObjCRetainableType()) {
+ expectedLifetime = Qualifiers::OCL_ExplicitNone;
+ selector = 2;
+ } else {
+ // We have a lifetime qualifier but no dominating property
+ // attribute. That's okay.
+ return;
+ }
+
+ if (propertyLifetime == expectedLifetime) return;
+
+ property->setInvalidDecl();
+ S.Diag(property->getLocation(),
+ diag::err_arc_inconsistent_property_ownership)
+ << property->getDeclName()
+ << selector
+ << propertyLifetime;
+}
+
Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
FieldDeclarator &FD,
ObjCDeclSpec &ODS,
@@ -34,6 +79,14 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
tok::ObjCKeywordKind MethodImplKind,
DeclContext *lexicalDC) {
unsigned Attributes = ODS.getPropertyAttributes();
+ TypeSourceInfo *TSI = GetTypeForDeclarator(FD.D, S);
+ QualType T = TSI->getType();
+ if ((getLangOptions().getGCMode() != LangOptions::NonGC &&
+ T.isObjCGCWeak()) ||
+ (getLangOptions().ObjCAutoRefCount &&
+ T.getObjCLifetime() == Qualifiers::OCL_Weak))
+ Attributes |= ObjCDeclSpec::DQ_PR_weak;
+
bool isReadWrite = ((Attributes & ObjCDeclSpec::DQ_PR_readwrite) ||
// default is readwrite!
!(Attributes & ObjCDeclSpec::DQ_PR_readonly));
@@ -42,9 +95,10 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
bool isAssign = ((Attributes & ObjCDeclSpec::DQ_PR_assign) ||
(isReadWrite &&
!(Attributes & ObjCDeclSpec::DQ_PR_retain) &&
- !(Attributes & ObjCDeclSpec::DQ_PR_copy)));
-
- TypeSourceInfo *TSI = GetTypeForDeclarator(FD.D, S);
+ !(Attributes & ObjCDeclSpec::DQ_PR_strong) &&
+ !(Attributes & ObjCDeclSpec::DQ_PR_copy) &&
+ !(Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained) &&
+ !(Attributes & ObjCDeclSpec::DQ_PR_weak)));
// Proceed with constructing the ObjCPropertDecls.
ObjCContainerDecl *ClassDecl =
@@ -58,20 +112,27 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
Attributes,
isOverridingProperty, TSI,
MethodImplKind);
- if (Res)
+ if (Res) {
CheckObjCPropertyAttributes(Res, AtLoc, Attributes);
+ if (getLangOptions().ObjCAutoRefCount)
+ checkARCPropertyDecl(*this, cast<ObjCPropertyDecl>(Res));
+ }
return Res;
}
- Decl *Res = CreatePropertyDecl(S, ClassDecl, AtLoc, FD,
- GetterSel, SetterSel,
- isAssign, isReadWrite,
- Attributes, TSI, MethodImplKind);
+ ObjCPropertyDecl *Res = CreatePropertyDecl(S, ClassDecl, AtLoc, FD,
+ GetterSel, SetterSel,
+ isAssign, isReadWrite,
+ Attributes, TSI, MethodImplKind);
if (lexicalDC)
Res->setLexicalDeclContext(lexicalDC);
// Validate the attributes on the @property.
CheckObjCPropertyAttributes(Res, AtLoc, Attributes);
+
+ if (getLangOptions().ObjCAutoRefCount)
+ checkARCPropertyDecl(*this, Res);
+
return Res;
}
@@ -118,6 +179,7 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl,
// Set setter/getter selector name. Needed later.
PDecl->setGetterName(GetterSel);
PDecl->setSetterName(SetterSel);
+ ProcessDeclAttributes(S, PDecl, FD.D);
DC->addDecl(PDecl);
// We need to look in the @interface to see if the @property was
@@ -139,10 +201,6 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl,
CreatePropertyDecl(S, CCPrimary, AtLoc,
FD, GetterSel, SetterSel, isAssign, isReadWrite,
Attributes, T, MethodImplKind, DC);
- // Mark written attribute as having no attribute because
- // this is not a user-written property declaration in primary
- // class.
- PDecl->setPropertyAttributesAsWritten(ObjCPropertyDecl::OBJC_PR_noattr);
// A case of continuation class adding a new property in the class. This
// is not what it was meant for. However, gcc supports it and so should we.
@@ -158,6 +216,7 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl,
if (isReadWrite && (PIkind & ObjCPropertyDecl::OBJC_PR_readonly)) {
unsigned retainCopyNonatomic =
(ObjCPropertyDecl::OBJC_PR_retain |
+ ObjCPropertyDecl::OBJC_PR_strong |
ObjCPropertyDecl::OBJC_PR_copy |
ObjCPropertyDecl::OBJC_PR_nonatomic);
if ((Attributes & retainCopyNonatomic) !=
@@ -189,6 +248,8 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl,
PIDecl->makeitReadWriteAttribute();
if (Attributes & ObjCDeclSpec::DQ_PR_retain)
PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain);
+ if (Attributes & ObjCDeclSpec::DQ_PR_strong)
+ PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_strong);
if (Attributes & ObjCDeclSpec::DQ_PR_copy)
PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy);
PIDecl->setSetterName(SetterSel);
@@ -272,6 +333,35 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
PDecl->setGetterName(GetterSel);
PDecl->setSetterName(SetterSel);
+ unsigned attributesAsWritten = 0;
+ if (Attributes & ObjCDeclSpec::DQ_PR_readonly)
+ attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_readonly;
+ if (Attributes & ObjCDeclSpec::DQ_PR_readwrite)
+ attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_readwrite;
+ if (Attributes & ObjCDeclSpec::DQ_PR_getter)
+ attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_getter;
+ if (Attributes & ObjCDeclSpec::DQ_PR_setter)
+ attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_setter;
+ if (Attributes & ObjCDeclSpec::DQ_PR_assign)
+ attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_assign;
+ if (Attributes & ObjCDeclSpec::DQ_PR_retain)
+ attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_retain;
+ if (Attributes & ObjCDeclSpec::DQ_PR_strong)
+ attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_strong;
+ if (Attributes & ObjCDeclSpec::DQ_PR_weak)
+ attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_weak;
+ if (Attributes & ObjCDeclSpec::DQ_PR_copy)
+ attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_copy;
+ if (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained)
+ attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_unsafe_unretained;
+ if (Attributes & ObjCDeclSpec::DQ_PR_nonatomic)
+ attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_nonatomic;
+ if (Attributes & ObjCDeclSpec::DQ_PR_atomic)
+ attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_atomic;
+
+ PDecl->setPropertyAttributesAsWritten(
+ (ObjCPropertyDecl::PropertyAttributeKind)attributesAsWritten);
+
if (Attributes & ObjCDeclSpec::DQ_PR_readonly)
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readonly);
@@ -287,9 +377,18 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
if (Attributes & ObjCDeclSpec::DQ_PR_retain)
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain);
+ if (Attributes & ObjCDeclSpec::DQ_PR_strong)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_strong);
+
+ if (Attributes & ObjCDeclSpec::DQ_PR_weak)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_weak);
+
if (Attributes & ObjCDeclSpec::DQ_PR_copy)
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy);
+ if (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_unsafe_unretained);
+
if (isAssign)
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_assign);
@@ -298,8 +397,12 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
else if (Attributes & ObjCDeclSpec::DQ_PR_atomic)
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_atomic);
- PDecl->setPropertyAttributesAsWritten(PDecl->getPropertyAttributes());
-
+ // 'unsafe_unretained' is alias for 'assign'.
+ if (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_assign);
+ if (isAssign)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_unsafe_unretained);
+
if (MethodImplKind == tok::objc_required)
PDecl->setPropertyImplementation(ObjCPropertyDecl::Required);
else if (MethodImplKind == tok::objc_optional)
@@ -308,6 +411,93 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
return PDecl;
}
+static void checkARCPropertyImpl(Sema &S, SourceLocation propertyImplLoc,
+ ObjCPropertyDecl *property,
+ ObjCIvarDecl *ivar) {
+ if (property->isInvalidDecl() || ivar->isInvalidDecl()) return;
+
+ QualType propertyType = property->getType();
+ Qualifiers::ObjCLifetime propertyLifetime = propertyType.getObjCLifetime();
+ ObjCPropertyDecl::PropertyAttributeKind propertyKind
+ = property->getPropertyAttributes();
+
+ QualType ivarType = ivar->getType();
+ Qualifiers::ObjCLifetime ivarLifetime = ivarType.getObjCLifetime();
+
+ // Case 1: strong properties.
+ if (propertyLifetime == Qualifiers::OCL_Strong ||
+ (propertyKind & (ObjCPropertyDecl::OBJC_PR_retain |
+ ObjCPropertyDecl::OBJC_PR_strong |
+ ObjCPropertyDecl::OBJC_PR_copy))) {
+ switch (ivarLifetime) {
+ case Qualifiers::OCL_Strong:
+ // Okay.
+ return;
+
+ case Qualifiers::OCL_None:
+ case Qualifiers::OCL_Autoreleasing:
+ // These aren't valid lifetimes for object ivars; don't diagnose twice.
+ return;
+
+ case Qualifiers::OCL_ExplicitNone:
+ case Qualifiers::OCL_Weak:
+ S.Diag(propertyImplLoc, diag::err_arc_strong_property_ownership)
+ << property->getDeclName()
+ << ivar->getDeclName()
+ << ivarLifetime;
+ break;
+ }
+
+ // Case 2: weak properties.
+ } else if (propertyLifetime == Qualifiers::OCL_Weak ||
+ (propertyKind & ObjCPropertyDecl::OBJC_PR_weak)) {
+ switch (ivarLifetime) {
+ case Qualifiers::OCL_Weak:
+ // Okay.
+ return;
+
+ case Qualifiers::OCL_None:
+ case Qualifiers::OCL_Autoreleasing:
+ // These aren't valid lifetimes for object ivars; don't diagnose twice.
+ return;
+
+ case Qualifiers::OCL_ExplicitNone:
+ case Qualifiers::OCL_Strong:
+ S.Diag(propertyImplLoc, diag::error_weak_property)
+ << property->getDeclName()
+ << ivar->getDeclName();
+ break;
+ }
+
+ // Case 3: assign properties.
+ } else if ((propertyKind & ObjCPropertyDecl::OBJC_PR_assign) &&
+ propertyType->isObjCRetainableType()) {
+ switch (ivarLifetime) {
+ case Qualifiers::OCL_ExplicitNone:
+ // Okay.
+ return;
+
+ case Qualifiers::OCL_None:
+ case Qualifiers::OCL_Autoreleasing:
+ // These aren't valid lifetimes for object ivars; don't diagnose twice.
+ return;
+
+ case Qualifiers::OCL_Weak:
+ case Qualifiers::OCL_Strong:
+ S.Diag(propertyImplLoc, diag::err_arc_assign_property_ownership)
+ << property->getDeclName()
+ << ivar->getDeclName();
+ break;
+ }
+
+ // Any other property should be ignored.
+ } else {
+ return;
+ }
+
+ S.Diag(property->getLocation(), diag::note_property_declare);
+}
+
/// ActOnPropertyImplDecl - This routine performs semantic checks and
/// builds the AST node for a property implementation declaration; declared
@@ -396,9 +586,18 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
ObjCIvarDecl *Ivar = 0;
// Check that we have a valid, previously declared ivar for @synthesize
if (Synthesize) {
+ if (getLangOptions().ObjCAutoRefCount &&
+ !property->hasWrittenStorageAttribute() &&
+ property->getType()->isObjCRetainableType()) {
+ Diag(PropertyLoc, diag::err_arc_objc_property_default_assign_on_object);
+ Diag(property->getLocation(), diag::note_property_declare);
+ }
+
// @synthesize
if (!PropertyIvar)
PropertyIvar = PropertyId;
+ ObjCPropertyDecl::PropertyAttributeKind kind
+ = property->getPropertyAttributes();
QualType PropType = Context.getCanonicalType(property->getType());
QualType PropertyIvarType = PropType;
if (PropType->isReferenceType())
@@ -407,6 +606,45 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
ObjCInterfaceDecl *ClassDeclared;
Ivar = IDecl->lookupInstanceVariable(PropertyIvar, ClassDeclared);
if (!Ivar) {
+ // In ARC, give the ivar a lifetime qualifier based on its
+ // property attributes.
+ if (getLangOptions().ObjCAutoRefCount &&
+ !PropertyIvarType.getObjCLifetime()) {
+
+ // retain/copy have retaining lifetime.
+ if (kind & (ObjCPropertyDecl::OBJC_PR_retain |
+ ObjCPropertyDecl::OBJC_PR_strong |
+ ObjCPropertyDecl::OBJC_PR_copy)) {
+ Qualifiers qs;
+ qs.addObjCLifetime(Qualifiers::OCL_Strong);
+ PropertyIvarType = Context.getQualifiedType(PropertyIvarType, qs);
+ }
+ else if (kind & ObjCPropertyDecl::OBJC_PR_weak) {
+ if (!getLangOptions().ObjCRuntimeHasWeak) {
+ Diag(PropertyLoc, diag::err_arc_weak_no_runtime);
+ Diag(property->getLocation(), diag::note_property_declare);
+ }
+ Qualifiers qs;
+ qs.addObjCLifetime(Qualifiers::OCL_Weak);
+ PropertyIvarType = Context.getQualifiedType(PropertyIvarType, qs);
+ }
+ else if (kind & ObjCPropertyDecl::OBJC_PR_assign &&
+ PropertyIvarType->isObjCRetainableType()) {
+ // assume that an 'assign' property synthesizes __unsafe_unretained
+ // ivar
+ Qualifiers qs;
+ qs.addObjCLifetime(Qualifiers::OCL_ExplicitNone);
+ PropertyIvarType = Context.getQualifiedType(PropertyIvarType, qs);
+ }
+ }
+
+ if (kind & ObjCPropertyDecl::OBJC_PR_weak &&
+ !getLangOptions().ObjCAutoRefCount &&
+ getLangOptions().getGCMode() == LangOptions::NonGC) {
+ Diag(PropertyLoc, diag::error_synthesize_weak_non_arc_or_gc);
+ Diag(property->getLocation(), diag::note_property_declare);
+ }
+
Ivar = ObjCIvarDecl::Create(Context, ClassImpDecl,
PropertyLoc, PropertyLoc, PropertyIvar,
PropertyIvarType, /*Dinfo=*/0,
@@ -435,7 +673,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
if (PropertyIvarType != IvarType) {
bool compat = false;
if (isa<ObjCObjectPointerType>(PropertyIvarType)
- && isa<ObjCObjectPointerType>(IvarType))
+ && isa<ObjCObjectPointerType>(IvarType))
compat =
Context.canAssignObjCInterfaces(
PropertyIvarType->getAs<ObjCObjectPointerType>(),
@@ -470,12 +708,13 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
// Fall thru - see previous comment
}
// __weak is explicit. So it works on Canonical type.
- if (PropType.isObjCGCWeak() && !IvarType.isObjCGCWeak() &&
- getLangOptions().getGCMode() != LangOptions::NonGC) {
+ if ((PropType.isObjCGCWeak() && !IvarType.isObjCGCWeak() &&
+ getLangOptions().getGCMode() != LangOptions::NonGC)) {
Diag(PropertyLoc, diag::error_weak_property)
<< property->getDeclName() << Ivar->getDeclName();
// Fall thru - see previous comment
}
+ // Fall thru - see previous comment
if ((property->getType()->isObjCObjectPointerType() ||
PropType.isObjCGCStrong()) && IvarType.isObjCGCWeak() &&
getLangOptions().getGCMode() != LangOptions::NonGC) {
@@ -484,9 +723,12 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
// Fall thru - see previous comment
}
}
+ if (getLangOptions().ObjCAutoRefCount)
+ checkARCPropertyImpl(*this, PropertyLoc, property, Ivar);
} else if (PropertyIvar)
// @dynamic
Diag(PropertyLoc, diag::error_dynamic_property_ivar_decl);
+
assert (property && "ActOnPropertyImplDecl - property declaration missing");
ObjCPropertyImplDecl *PIDecl =
ObjCPropertyImplDecl::Create(Context, CurContext, AtLoc, PropertyLoc,
@@ -523,6 +765,12 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
PIDecl->setGetterCXXConstructor(ResExpr);
}
}
+ if (property->hasAttr<NSReturnsNotRetainedAttr>() &&
+ !getterMethod->hasAttr<NSReturnsNotRetainedAttr>()) {
+ Diag(getterMethod->getLocation(),
+ diag::warn_property_getter_owning_mismatch);
+ Diag(property->getLocation(), diag::note_property_declare);
+ }
}
if (ObjCMethodDecl *setterMethod = property->getSetterMethodDecl()) {
setterMethod->createImplicitParams(Context, IDecl);
@@ -632,10 +880,19 @@ Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property,
!= (SAttr & ObjCPropertyDecl::OBJC_PR_copy))
Diag(Property->getLocation(), diag::warn_property_attribute)
<< Property->getDeclName() << "copy" << inheritedName;
- else if ((CAttr & ObjCPropertyDecl::OBJC_PR_retain)
- != (SAttr & ObjCPropertyDecl::OBJC_PR_retain))
- Diag(Property->getLocation(), diag::warn_property_attribute)
- << Property->getDeclName() << "retain" << inheritedName;
+ else {
+ unsigned CAttrRetain =
+ (CAttr &
+ (ObjCPropertyDecl::OBJC_PR_retain | ObjCPropertyDecl::OBJC_PR_strong));
+ unsigned SAttrRetain =
+ (SAttr &
+ (ObjCPropertyDecl::OBJC_PR_retain | ObjCPropertyDecl::OBJC_PR_strong));
+ bool CStrong = (CAttrRetain != 0);
+ bool SStrong = (SAttrRetain != 0);
+ if (CStrong != SStrong)
+ Diag(Property->getLocation(), diag::warn_property_attribute)
+ << Property->getDeclName() << "retain (or strong)" << inheritedName;
+ }
if ((CAttr & ObjCPropertyDecl::OBJC_PR_nonatomic)
!= (SAttr & ObjCPropertyDecl::OBJC_PR_nonatomic))
@@ -653,13 +910,16 @@ Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property,
QualType RHSType =
Context.getCanonicalType(Property->getType());
- if (!Context.typesAreCompatible(LHSType, RHSType)) {
- // FIXME: Incorporate this test with typesAreCompatible.
- if (LHSType->isObjCQualifiedIdType() && RHSType->isObjCQualifiedIdType())
- if (Context.ObjCQualifiedIdTypesAreCompatible(LHSType, RHSType, false))
- return;
- Diag(Property->getLocation(), diag::warn_property_types_are_incompatible)
- << Property->getType() << SuperProperty->getType() << inheritedName;
+ if (!Context.propertyTypesAreCompatible(LHSType, RHSType)) {
+ // Do cases not handled in above.
+ // FIXME. For future support of covariant property types, revisit this.
+ bool IncompatibleObjC = false;
+ QualType ConvertedType;
+ if (!isObjCPointerConversion(RHSType, LHSType,
+ ConvertedType, IncompatibleObjC) ||
+ IncompatibleObjC)
+ Diag(Property->getLocation(), diag::warn_property_types_are_incompatible)
+ << Property->getType() << SuperProperty->getType() << inheritedName;
}
}
@@ -1050,7 +1310,7 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
// Is there a matching propery synthesize/dynamic?
if (Prop->isInvalidDecl() ||
Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional ||
- PropImplMap.count(Prop))
+ PropImplMap.count(Prop) || Prop->hasAttr<UnavailableAttr>())
continue;
if (!InsMap.count(Prop->getGetterName())) {
Diag(Prop->getLocation(),
@@ -1135,6 +1395,35 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl,
}
}
+void Sema::DiagnoseOwningPropertyGetterSynthesis(const ObjCImplementationDecl *D) {
+ if (getLangOptions().getGCMode() == LangOptions::GCOnly)
+ return;
+
+ for (ObjCImplementationDecl::propimpl_iterator
+ i = D->propimpl_begin(), e = D->propimpl_end(); i != e; ++i) {
+ ObjCPropertyImplDecl *PID = *i;
+ if (PID->getPropertyImplementation() != ObjCPropertyImplDecl::Synthesize)
+ continue;
+
+ const ObjCPropertyDecl *PD = PID->getPropertyDecl();
+ if (PD && !PD->hasAttr<NSReturnsNotRetainedAttr>() &&
+ !D->getInstanceMethod(PD->getGetterName())) {
+ ObjCMethodDecl *method = PD->getGetterMethodDecl();
+ if (!method)
+ continue;
+ ObjCMethodFamily family = method->getMethodFamily();
+ if (family == OMF_alloc || family == OMF_copy ||
+ family == OMF_mutableCopy || family == OMF_new) {
+ if (getLangOptions().ObjCAutoRefCount)
+ Diag(PID->getLocation(), diag::err_ownin_getter_rule);
+ else
+ Diag(PID->getLocation(), diag::warn_ownin_getter_rule);
+ Diag(PD->getLocation(), diag::note_property_declare);
+ }
+ }
+ }
+}
+
/// AddPropertyAttrs - Propagates attributes from a property to the
/// implicitly-declared getter or setter for that property.
static void AddPropertyAttrs(Sema &S, ObjCMethodDecl *PropertyMethod,
@@ -1214,6 +1503,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
// and the real context should be the same.
if (lexicalDC)
GetterMethod->setLexicalDeclContext(lexicalDC);
+ if (property->hasAttr<NSReturnsNotRetainedAttr>())
+ GetterMethod->addAttr(
+ ::new (Context) NSReturnsNotRetainedAttr(Loc, Context));
} else
// A user declared getter will be synthesize when @synthesize of
// the property with the same name is seen in the @implementation
@@ -1245,7 +1537,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
ParmVarDecl *Argument = ParmVarDecl::Create(Context, SetterMethod,
Loc, Loc,
property->getIdentifier(),
- property->getType(),
+ property->getType().getUnqualifiedType(),
/*TInfo=*/0,
SC_None,
SC_None,
@@ -1287,7 +1579,7 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl,
SourceLocation Loc,
unsigned &Attributes) {
// FIXME: Improve the reported location.
- if (!PDecl)
+ if (!PDecl || PDecl->isInvalidDecl())
return;
ObjCPropertyDecl *PropertyDecl = cast<ObjCPropertyDecl>(PDecl);
@@ -1297,12 +1589,16 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl,
if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
(Attributes & (ObjCDeclSpec::DQ_PR_readwrite |
ObjCDeclSpec::DQ_PR_assign |
+ ObjCDeclSpec::DQ_PR_unsafe_unretained |
ObjCDeclSpec::DQ_PR_copy |
- ObjCDeclSpec::DQ_PR_retain))) {
+ ObjCDeclSpec::DQ_PR_retain |
+ ObjCDeclSpec::DQ_PR_strong))) {
const char * which = (Attributes & ObjCDeclSpec::DQ_PR_readwrite) ?
"readwrite" :
(Attributes & ObjCDeclSpec::DQ_PR_assign) ?
"assign" :
+ (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained) ?
+ "unsafe_unretained" :
(Attributes & ObjCDeclSpec::DQ_PR_copy) ?
"copy" : "retain";
@@ -1313,14 +1609,15 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl,
}
// Check for copy or retain on non-object types.
- if ((Attributes & (ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain)) &&
- !PropertyTy->isObjCObjectPointerType() &&
- !PropertyTy->isBlockPointerType() &&
- !Context.isObjCNSObjectType(PropertyTy) &&
+ if ((Attributes & (ObjCDeclSpec::DQ_PR_weak | ObjCDeclSpec::DQ_PR_copy |
+ ObjCDeclSpec::DQ_PR_retain | ObjCDeclSpec::DQ_PR_strong)) &&
+ !PropertyTy->isObjCRetainableType() &&
!PropertyDecl->getAttr<ObjCNSObjectAttr>()) {
Diag(Loc, diag::err_objc_property_requires_object)
- << (Attributes & ObjCDeclSpec::DQ_PR_copy ? "copy" : "retain");
- Attributes &= ~(ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain);
+ << (Attributes & ObjCDeclSpec::DQ_PR_weak ? "weak" :
+ Attributes & ObjCDeclSpec::DQ_PR_copy ? "copy" : "retain (or strong)");
+ Attributes &= ~(ObjCDeclSpec::DQ_PR_weak | ObjCDeclSpec::DQ_PR_copy |
+ ObjCDeclSpec::DQ_PR_retain | ObjCDeclSpec::DQ_PR_strong);
}
// Check for more than one of { assign, copy, retain }.
@@ -1335,18 +1632,75 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl,
<< "assign" << "retain";
Attributes &= ~ObjCDeclSpec::DQ_PR_retain;
}
+ if (Attributes & ObjCDeclSpec::DQ_PR_strong) {
+ Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
+ << "assign" << "strong";
+ Attributes &= ~ObjCDeclSpec::DQ_PR_strong;
+ }
+ if (getLangOptions().ObjCAutoRefCount &&
+ (Attributes & ObjCDeclSpec::DQ_PR_weak)) {
+ Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
+ << "assign" << "weak";
+ Attributes &= ~ObjCDeclSpec::DQ_PR_weak;
+ }
+ } else if (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained) {
+ if (Attributes & ObjCDeclSpec::DQ_PR_copy) {
+ Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
+ << "unsafe_unretained" << "copy";
+ Attributes &= ~ObjCDeclSpec::DQ_PR_copy;
+ }
+ if (Attributes & ObjCDeclSpec::DQ_PR_retain) {
+ Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
+ << "unsafe_unretained" << "retain";
+ Attributes &= ~ObjCDeclSpec::DQ_PR_retain;
+ }
+ if (Attributes & ObjCDeclSpec::DQ_PR_strong) {
+ Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
+ << "unsafe_unretained" << "strong";
+ Attributes &= ~ObjCDeclSpec::DQ_PR_strong;
+ }
+ if (getLangOptions().ObjCAutoRefCount &&
+ (Attributes & ObjCDeclSpec::DQ_PR_weak)) {
+ Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
+ << "unsafe_unretained" << "weak";
+ Attributes &= ~ObjCDeclSpec::DQ_PR_weak;
+ }
} else if (Attributes & ObjCDeclSpec::DQ_PR_copy) {
if (Attributes & ObjCDeclSpec::DQ_PR_retain) {
Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
<< "copy" << "retain";
Attributes &= ~ObjCDeclSpec::DQ_PR_retain;
}
+ if (Attributes & ObjCDeclSpec::DQ_PR_strong) {
+ Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
+ << "copy" << "strong";
+ Attributes &= ~ObjCDeclSpec::DQ_PR_strong;
+ }
+ if (Attributes & ObjCDeclSpec::DQ_PR_weak) {
+ Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
+ << "copy" << "weak";
+ Attributes &= ~ObjCDeclSpec::DQ_PR_weak;
+ }
+ }
+ else if ((Attributes & ObjCDeclSpec::DQ_PR_retain) &&
+ (Attributes & ObjCDeclSpec::DQ_PR_weak)) {
+ Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
+ << "retain" << "weak";
+ Attributes &= ~ObjCDeclSpec::DQ_PR_weak;
+ }
+ else if ((Attributes & ObjCDeclSpec::DQ_PR_strong) &&
+ (Attributes & ObjCDeclSpec::DQ_PR_weak)) {
+ Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
+ << "strong" << "weak";
+ Attributes &= ~ObjCDeclSpec::DQ_PR_weak;
}
// Warn if user supplied no assignment attribute, property is
// readwrite, and this is an object type.
if (!(Attributes & (ObjCDeclSpec::DQ_PR_assign | ObjCDeclSpec::DQ_PR_copy |
- ObjCDeclSpec::DQ_PR_retain)) &&
+ ObjCDeclSpec::DQ_PR_unsafe_unretained |
+ ObjCDeclSpec::DQ_PR_retain | ObjCDeclSpec::DQ_PR_strong |
+ ObjCDeclSpec::DQ_PR_weak)) &&
!(Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
PropertyTy->isObjCObjectPointerType()) {
// Skip this warning in gc-only mode.
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 4bba6f8877bf..437b2b5c6d43 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -38,8 +38,10 @@ using namespace sema;
/// function.
static ExprResult
CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn,
- SourceLocation Loc = SourceLocation()) {
- ExprResult E = S.Owned(new (S.Context) DeclRefExpr(Fn, Fn->getType(), VK_LValue, Loc));
+ SourceLocation Loc = SourceLocation(),
+ const DeclarationNameLoc &LocInfo = DeclarationNameLoc()){
+ ExprResult E = S.Owned(new (S.Context) DeclRefExpr(Fn, Fn->getType(),
+ VK_LValue, Loc, LocInfo));
E = S.DefaultFunctionArrayConversion(E.take());
if (E.isInvalid())
return ExprError();
@@ -49,7 +51,8 @@ CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn,
static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
bool InOverloadResolution,
StandardConversionSequence &SCS,
- bool CStyle);
+ bool CStyle,
+ bool AllowObjCWritebackConversion);
static bool IsTransparentUnionStandardConversion(Sema &S, Expr* From,
QualType &ToType,
@@ -106,6 +109,7 @@ GetConversionCategory(ImplicitConversionKind Kind) {
ICC_Conversion,
ICC_Conversion,
ICC_Conversion,
+ ICC_Conversion,
ICC_Conversion
};
return Category[(int)Kind];
@@ -138,7 +142,8 @@ ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind) {
ICR_Conversion,
ICR_Complex_Real_Conversion,
ICR_Conversion,
- ICR_Conversion
+ ICR_Conversion,
+ ICR_Writeback_Conversion
};
return Rank[(int)Kind];
}
@@ -170,6 +175,7 @@ const char* GetImplicitConversionName(ImplicitConversionKind Kind) {
"Complex-real conversion",
"Block Pointer conversion",
"Transparent Union Conversion"
+ "Writeback conversion"
};
return Name[Kind];
}
@@ -181,12 +187,14 @@ void StandardConversionSequence::setAsIdentityConversion() {
Second = ICK_Identity;
Third = ICK_Identity;
DeprecatedStringLiteralToCharPtr = false;
+ QualificationIncludesObjCLifetime = false;
ReferenceBinding = false;
DirectBinding = false;
IsLvalueReference = true;
BindsToFunctionLvalue = false;
BindsToRvalue = false;
BindsImplicitObjectArgumentWithoutRefQualifier = false;
+ ObjCLifetimeConversionBinding = false;
CopyConstructor = 0;
}
@@ -730,6 +738,15 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
return false;
}
+/// \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 Sema::isFunctionConsideredUnavailable(FunctionDecl *FD) {
+ return FD->isUnavailable() && !cast<Decl>(CurContext)->isUnavailable();
+}
+
/// TryImplicitConversion - Attempt to perform an implicit conversion
/// from the given expression (Expr) to the given type (ToType). This
/// function returns an implicit conversion sequence that can be used
@@ -753,15 +770,20 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
/// not permitted.
/// If @p AllowExplicit, then explicit user-defined conversions are
/// permitted.
+///
+/// \param AllowObjCWritebackConversion Whether we allow the Objective-C
+/// writeback conversion, which allows __autoreleasing id* parameters to
+/// be initialized with __strong id* or __weak id* arguments.
static ImplicitConversionSequence
TryImplicitConversion(Sema &S, Expr *From, QualType ToType,
bool SuppressUserConversions,
bool AllowExplicit,
bool InOverloadResolution,
- bool CStyle) {
+ bool CStyle,
+ bool AllowObjCWritebackConversion) {
ImplicitConversionSequence ICS;
if (IsStandardConversion(S, From, ToType, InOverloadResolution,
- ICS.Standard, CStyle)) {
+ ICS.Standard, CStyle, AllowObjCWritebackConversion)){
ICS.setStandard();
return ICS;
}
@@ -867,24 +889,17 @@ TryImplicitConversion(Sema &S, Expr *From, QualType ToType,
return ICS;
}
-bool Sema::TryImplicitConversion(InitializationSequence &Sequence,
- const InitializedEntity &Entity,
- Expr *Initializer,
- bool SuppressUserConversions,
- bool AllowExplicitConversions,
- bool InOverloadResolution,
- bool CStyle) {
- ImplicitConversionSequence ICS
- = clang::TryImplicitConversion(*this, Initializer, Entity.getType(),
- SuppressUserConversions,
- AllowExplicitConversions,
- InOverloadResolution,
- CStyle);
- if (ICS.isBad()) return true;
-
- // Perform the actual conversion.
- Sequence.AddConversionSequenceStep(ICS, Entity.getType());
- return false;
+ImplicitConversionSequence
+Sema::TryImplicitConversion(Expr *From, QualType ToType,
+ bool SuppressUserConversions,
+ bool AllowExplicit,
+ bool InOverloadResolution,
+ bool CStyle,
+ bool AllowObjCWritebackConversion) {
+ return clang::TryImplicitConversion(*this, From, ToType,
+ SuppressUserConversions, AllowExplicit,
+ InOverloadResolution, CStyle,
+ AllowObjCWritebackConversion);
}
/// PerformImplicitConversion - Perform an implicit conversion of the
@@ -903,18 +918,25 @@ ExprResult
Sema::PerformImplicitConversion(Expr *From, QualType ToType,
AssignmentAction Action, bool AllowExplicit,
ImplicitConversionSequence& ICS) {
+ // Objective-C ARC: Determine whether we will allow the writeback conversion.
+ bool AllowObjCWritebackConversion
+ = getLangOptions().ObjCAutoRefCount &&
+ (Action == AA_Passing || Action == AA_Sending);
+
+
ICS = clang::TryImplicitConversion(*this, From, ToType,
/*SuppressUserConversions=*/false,
AllowExplicit,
/*InOverloadResolution=*/false,
- /*CStyle=*/false);
+ /*CStyle=*/false,
+ AllowObjCWritebackConversion);
return PerformImplicitConversion(From, ToType, ICS, Action);
}
/// \brief Determine whether the conversion from FromType to ToType is a valid
/// conversion that strips "noreturn" off the nested function type.
-static bool IsNoReturnConversion(ASTContext &Context, QualType FromType,
- QualType ToType, QualType &ResultTy) {
+bool Sema::IsNoReturnConversion(QualType FromType, QualType ToType,
+ QualType &ResultTy) {
if (Context.hasSameUnqualifiedType(FromType, ToType))
return false;
@@ -1016,7 +1038,8 @@ static bool IsVectorConversion(ASTContext &Context, QualType FromType,
static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
bool InOverloadResolution,
StandardConversionSequence &SCS,
- bool CStyle) {
+ bool CStyle,
+ bool AllowObjCWritebackConversion) {
QualType FromType = From->getType();
// Standard conversions (C++ [conv])
@@ -1054,7 +1077,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
S.ExtractUnqualifiedFunctionType(ToType), FromType)) {
QualType resultTy;
// if the function type matches except for [[noreturn]], it's ok
- if (!IsNoReturnConversion(S.Context, FromType,
+ if (!S.IsNoReturnConversion(FromType,
S.ExtractUnqualifiedFunctionType(ToType), resultTy))
// otherwise, only a boolean conversion is standard
if (!ToType->isBooleanType())
@@ -1123,6 +1146,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
// conversion (4.4). (C++ 4.2p2)
SCS.Second = ICK_Identity;
SCS.Third = ICK_Qualification;
+ SCS.QualificationIncludesObjCLifetime = false;
SCS.setAllToTypes(FromType);
return true;
}
@@ -1199,7 +1223,10 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
SCS.Second = ICK_Floating_Integral;
FromType = ToType.getUnqualifiedType();
} else if (S.IsBlockPointerConversion(FromType, ToType, FromType)) {
- SCS.Second = ICK_Block_Pointer_Conversion;
+ SCS.Second = ICK_Block_Pointer_Conversion;
+ } else if (AllowObjCWritebackConversion &&
+ S.isObjCWritebackConversion(FromType, ToType, FromType)) {
+ SCS.Second = ICK_Writeback_Conversion;
} else if (S.IsPointerConversion(From, FromType, ToType, InOverloadResolution,
FromType, IncompatibleObjC)) {
// Pointer conversions (C++ 4.10).
@@ -1218,7 +1245,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
// Compatible conversions (Clang extension for C function overloading)
SCS.Second = ICK_Compatible_Conversion;
FromType = ToType.getUnqualifiedType();
- } else if (IsNoReturnConversion(S.Context, FromType, ToType, FromType)) {
+ } else if (S.IsNoReturnConversion(FromType, ToType, FromType)) {
// Treat a conversion that strips "noreturn" as an identity conversion.
SCS.Second = ICK_NoReturn_Adjustment;
} else if (IsTransparentUnionStandardConversion(S, From, ToType,
@@ -1235,8 +1262,11 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
QualType CanonFrom;
QualType CanonTo;
// The third conversion can be a qualification conversion (C++ 4p1).
- if (S.IsQualificationConversion(FromType, ToType, CStyle)) {
+ bool ObjCLifetimeConversion;
+ if (S.IsQualificationConversion(FromType, ToType, CStyle,
+ ObjCLifetimeConversion)) {
SCS.Third = ICK_Qualification;
+ SCS.QualificationIncludesObjCLifetime = ObjCLifetimeConversion;
FromType = ToType;
CanonFrom = S.Context.getCanonicalType(FromType);
CanonTo = S.Context.getCanonicalType(ToType);
@@ -1253,7 +1283,8 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
if (CanonFrom.getLocalUnqualifiedType()
== CanonTo.getLocalUnqualifiedType() &&
(CanonFrom.getLocalCVRQualifiers() != CanonTo.getLocalCVRQualifiers()
- || CanonFrom.getObjCGCAttr() != CanonTo.getObjCGCAttr())) {
+ || CanonFrom.getObjCGCAttr() != CanonTo.getObjCGCAttr()
+ || CanonFrom.getObjCLifetime() != CanonTo.getObjCLifetime())) {
FromType = ToType;
CanonFrom = CanonTo;
}
@@ -1284,7 +1315,8 @@ IsTransparentUnionStandardConversion(Sema &S, Expr* From,
for (RecordDecl::field_iterator it = UD->field_begin(),
itend = UD->field_end();
it != itend; ++it) {
- if (IsStandardConversion(S, From, it->getType(), InOverloadResolution, SCS, CStyle)) {
+ if (IsStandardConversion(S, From, it->getType(), InOverloadResolution, SCS,
+ CStyle, /*ObjCWritebackConversion=*/false)) {
ToType = it->getType();
return true;
}
@@ -1479,16 +1511,18 @@ bool Sema::IsComplexPromotion(QualType FromType, QualType ToType) {
/// same type qualifiers as FromPtr has on its pointee type. ToType,
/// if non-empty, will be a pointer to ToType that may or may not have
/// the right set of qualifiers on its pointee.
+///
static QualType
BuildSimilarlyQualifiedPointerType(const Type *FromPtr,
QualType ToPointee, QualType ToType,
- ASTContext &Context) {
+ ASTContext &Context,
+ bool StripObjCLifetime = false) {
assert((FromPtr->getTypeClass() == Type::Pointer ||
FromPtr->getTypeClass() == Type::ObjCObjectPointer) &&
"Invalid similarly-qualified pointer type");
- /// \brief Conversions to 'id' subsume cv-qualifier conversions.
- if (ToType->isObjCIdType() || ToType->isObjCQualifiedIdType())
+ /// Conversions to 'id' subsume cv-qualifier conversions.
+ if (ToType->isObjCIdType() || ToType->isObjCQualifiedIdType())
return ToType.getUnqualifiedType();
QualType CanonFromPointee
@@ -1496,6 +1530,9 @@ BuildSimilarlyQualifiedPointerType(const Type *FromPtr,
QualType CanonToPointee = Context.getCanonicalType(ToPointee);
Qualifiers Quals = CanonFromPointee.getQualifiers();
+ if (StripObjCLifetime)
+ Quals.removeObjCLifetime();
+
// Exact qualifier match -> return the pointer type we're converting to.
if (CanonToPointee.getLocalQualifiers() == Quals) {
// ToType is exactly what we need. Return it.
@@ -1599,7 +1636,8 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
// Beyond this point, both types need to be pointers
// , including objective-c pointers.
QualType ToPointeeType = ToTypePtr->getPointeeType();
- if (FromType->isObjCObjectPointerType() && ToPointeeType->isVoidType()) {
+ if (FromType->isObjCObjectPointerType() && ToPointeeType->isVoidType() &&
+ !getLangOptions().ObjCAutoRefCount) {
ConvertedType = BuildSimilarlyQualifiedPointerType(
FromType->getAs<ObjCObjectPointerType>(),
ToPointeeType,
@@ -1624,7 +1662,8 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
ToPointeeType->isVoidType()) {
ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
ToPointeeType,
- ToType, Context);
+ ToType, Context,
+ /*StripObjCLifetime=*/true);
return true;
}
@@ -1814,6 +1853,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
ToPointeeType->getAs<ObjCObjectPointerType>() &&
isObjCPointerConversion(FromPointeeType, ToPointeeType, ConvertedType,
IncompatibleObjC)) {
+
ConvertedType = Context.getPointerType(ConvertedType);
ConvertedType = AdoptQualifiers(Context, ConvertedType, FromQualifiers);
return true;
@@ -1885,6 +1925,73 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
return false;
}
+/// \brief Determine whether this is an Objective-C writeback conversion,
+/// used for parameter passing when performing automatic reference counting.
+///
+/// \param FromType The type we're converting form.
+///
+/// \param ToType The type we're converting to.
+///
+/// \param ConvertedType The type that will be produced after applying
+/// this conversion.
+bool Sema::isObjCWritebackConversion(QualType FromType, QualType ToType,
+ QualType &ConvertedType) {
+ if (!getLangOptions().ObjCAutoRefCount ||
+ Context.hasSameUnqualifiedType(FromType, ToType))
+ return false;
+
+ // Parameter must be a pointer to __autoreleasing (with no other qualifiers).
+ QualType ToPointee;
+ if (const PointerType *ToPointer = ToType->getAs<PointerType>())
+ ToPointee = ToPointer->getPointeeType();
+ else
+ return false;
+
+ Qualifiers ToQuals = ToPointee.getQualifiers();
+ if (!ToPointee->isObjCLifetimeType() ||
+ ToQuals.getObjCLifetime() != Qualifiers::OCL_Autoreleasing ||
+ !ToQuals.withoutObjCGLifetime().empty())
+ return false;
+
+ // Argument must be a pointer to __strong to __weak.
+ QualType FromPointee;
+ if (const PointerType *FromPointer = FromType->getAs<PointerType>())
+ FromPointee = FromPointer->getPointeeType();
+ else
+ return false;
+
+ Qualifiers FromQuals = FromPointee.getQualifiers();
+ if (!FromPointee->isObjCLifetimeType() ||
+ (FromQuals.getObjCLifetime() != Qualifiers::OCL_Strong &&
+ FromQuals.getObjCLifetime() != Qualifiers::OCL_Weak))
+ return false;
+
+ // Make sure that we have compatible qualifiers.
+ FromQuals.setObjCLifetime(Qualifiers::OCL_Autoreleasing);
+ if (!ToQuals.compatiblyIncludes(FromQuals))
+ return false;
+
+ // Remove qualifiers from the pointee type we're converting from; they
+ // aren't used in the compatibility check belong, and we'll be adding back
+ // qualifiers (with __autoreleasing) if the compatibility check succeeds.
+ FromPointee = FromPointee.getUnqualifiedType();
+
+ // The unqualified form of the pointee types must be compatible.
+ ToPointee = ToPointee.getUnqualifiedType();
+ bool IncompatibleObjC;
+ if (Context.typesAreCompatible(FromPointee, ToPointee))
+ FromPointee = ToPointee;
+ else if (!isObjCPointerConversion(FromPointee, ToPointee, FromPointee,
+ IncompatibleObjC))
+ return false;
+
+ /// \brief Construct the type we're converting to, which is a pointer to
+ /// __autoreleasing pointee.
+ FromPointee = Context.getQualifiedType(FromPointee, FromQuals);
+ ConvertedType = Context.getPointerType(FromPointee);
+ return true;
+}
+
bool Sema::IsBlockPointerConversion(QualType FromType, QualType ToType,
QualType& ConvertedType) {
QualType ToPointeeType;
@@ -2178,12 +2285,17 @@ bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType,
/// IsQualificationConversion - Determines whether the conversion from
/// an rvalue of type FromType to ToType is a qualification conversion
/// (C++ 4.4).
+///
+/// \param ObjCLifetimeConversion Output parameter that will be set to indicate
+/// when the qualification conversion involves a change in the Objective-C
+/// object lifetime.
bool
Sema::IsQualificationConversion(QualType FromType, QualType ToType,
- bool CStyle) {
+ bool CStyle, bool &ObjCLifetimeConversion) {
FromType = Context.getCanonicalType(FromType);
ToType = Context.getCanonicalType(ToType);
-
+ ObjCLifetimeConversion = false;
+
// If FromType and ToType are the same type, this is not a
// qualification conversion.
if (FromType.getUnqualifiedType() == ToType.getUnqualifiedType())
@@ -2206,6 +2318,21 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType,
Qualifiers FromQuals = FromType.getQualifiers();
Qualifiers ToQuals = ToType.getQualifiers();
+ // Objective-C ARC:
+ // Check Objective-C lifetime conversions.
+ if (FromQuals.getObjCLifetime() != ToQuals.getObjCLifetime() &&
+ UnwrappedAnyPointer) {
+ if (ToQuals.compatiblyIncludesObjCLifetime(FromQuals)) {
+ ObjCLifetimeConversion = true;
+ FromQuals.removeObjCLifetime();
+ ToQuals.removeObjCLifetime();
+ } else {
+ // Qualification conversions cannot cast between different
+ // Objective-C lifetime qualifiers.
+ return false;
+ }
+ }
+
// Allow addition/removal of GC attributes but not changing GC attributes.
if (FromQuals.getObjCGCAttr() != ToQuals.getObjCGCAttr() &&
(!FromQuals.hasObjCGCAttr() || !ToQuals.hasObjCGCAttr())) {
@@ -2713,6 +2840,15 @@ CompareStandardConversionSequences(Sema &S,
QualType UnqualT1 = S.Context.getUnqualifiedArrayType(T1, T1Quals);
QualType UnqualT2 = S.Context.getUnqualifiedArrayType(T2, T2Quals);
if (UnqualT1 == UnqualT2) {
+ // Objective-C++ ARC: If the references refer to objects with different
+ // lifetimes, prefer bindings that don't change lifetime.
+ if (SCS1.ObjCLifetimeConversionBinding !=
+ SCS2.ObjCLifetimeConversionBinding) {
+ return SCS1.ObjCLifetimeConversionBinding
+ ? ImplicitConversionSequence::Worse
+ : ImplicitConversionSequence::Better;
+ }
+
// If the type is an array type, promote the element qualifiers to the
// type for comparison.
if (isa<ArrayType>(T1) && T1Quals)
@@ -2722,7 +2858,7 @@ CompareStandardConversionSequences(Sema &S,
if (T2.isMoreQualifiedThan(T1))
return ImplicitConversionSequence::Better;
else if (T1.isMoreQualifiedThan(T2))
- return ImplicitConversionSequence::Worse;
+ return ImplicitConversionSequence::Worse;
}
}
@@ -2770,6 +2906,17 @@ CompareQualificationConversions(Sema &S,
ImplicitConversionSequence::CompareKind Result
= ImplicitConversionSequence::Indistinguishable;
+
+ // Objective-C++ ARC:
+ // Prefer qualification conversions not involving a change in lifetime
+ // to qualification conversions that do not change lifetime.
+ if (SCS1.QualificationIncludesObjCLifetime !=
+ SCS2.QualificationIncludesObjCLifetime) {
+ Result = SCS1.QualificationIncludesObjCLifetime
+ ? ImplicitConversionSequence::Worse
+ : ImplicitConversionSequence::Better;
+ }
+
while (S.Context.UnwrapSimilarPointerTypes(T1, T2)) {
// Within each iteration of the loop, we check the qualifiers to
// determine if this still looks like a qualification
@@ -3039,7 +3186,8 @@ Sema::ReferenceCompareResult
Sema::CompareReferenceRelationship(SourceLocation Loc,
QualType OrigT1, QualType OrigT2,
bool &DerivedToBase,
- bool &ObjCConversion) {
+ bool &ObjCConversion,
+ bool &ObjCLifetimeConversion) {
assert(!OrigT1->isReferenceType() &&
"T1 must be the pointee type of the reference type");
assert(!OrigT2->isReferenceType() && "T2 cannot be a reference type");
@@ -3056,6 +3204,7 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
// T1 is a base class of T2.
DerivedToBase = false;
ObjCConversion = false;
+ ObjCLifetimeConversion = false;
if (UnqualT1 == UnqualT2) {
// Nothing to do.
} else if (!RequireCompleteType(Loc, OrigT2, PDiag()) &&
@@ -3090,9 +3239,16 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
// qualifiers when performing these computations, so that e.g., an int in
// address space 1 is not reference-compatible with an int in address
// space 2.
+ if (T1Quals.getObjCLifetime() != T2Quals.getObjCLifetime() &&
+ T1Quals.compatiblyIncludesObjCLifetime(T2Quals)) {
+ T1Quals.removeObjCLifetime();
+ T2Quals.removeObjCLifetime();
+ ObjCLifetimeConversion = true;
+ }
+
if (T1Quals == T2Quals)
return Ref_Compatible;
- else if (T1.isMoreQualifiedThan(T2))
+ else if (T1Quals.compatiblyIncludes(T2Quals))
return Ref_Compatible_With_Added_Qualification;
else
return Ref_Related;
@@ -3135,13 +3291,14 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
if (AllowRvalues) {
bool DerivedToBase = false;
bool ObjCConversion = false;
+ bool ObjCLifetimeConversion = false;
if (!ConvTemplate &&
S.CompareReferenceRelationship(
DeclLoc,
Conv->getConversionType().getNonReferenceType()
.getUnqualifiedType(),
DeclType.getNonReferenceType().getUnqualifiedType(),
- DerivedToBase, ObjCConversion) ==
+ DerivedToBase, ObjCConversion, ObjCLifetimeConversion) ==
Sema::Ref_Incompatible)
continue;
} else {
@@ -3242,10 +3399,11 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType,
bool isRValRef = DeclType->isRValueReferenceType();
bool DerivedToBase = false;
bool ObjCConversion = false;
+ bool ObjCLifetimeConversion = false;
Expr::Classification InitCategory = Init->Classify(S.Context);
Sema::ReferenceCompareResult RefRelationship
= S.CompareReferenceRelationship(DeclLoc, T1, T2, DerivedToBase,
- ObjCConversion);
+ ObjCConversion, ObjCLifetimeConversion);
// C++0x [dcl.init.ref]p5:
@@ -3283,6 +3441,7 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType,
ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType();
ICS.Standard.BindsToRvalue = false;
ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false;
+ ICS.Standard.ObjCLifetimeConversionBinding = ObjCLifetimeConversion;
ICS.Standard.CopyConstructor = 0;
// Nothing more to do: the inaccessibility/ambiguity check for
@@ -3328,7 +3487,7 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType,
// -- If the initializer expression
//
// -- is an xvalue, class prvalue, array prvalue or function
- // lvalue and "cv1T1" is reference-compatible with "cv2 T2", or
+ // lvalue and "cv1 T1" is reference-compatible with "cv2 T2", or
if (RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification &&
(InitCategory.isXValue() ||
(InitCategory.isPRValue() && (T2->isRecordType() || T2->isArrayType())) ||
@@ -3356,6 +3515,7 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType,
ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType();
ICS.Standard.BindsToRvalue = InitCategory.isRValue();
ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false;
+ ICS.Standard.ObjCLifetimeConversionBinding = ObjCLifetimeConversion;
ICS.Standard.CopyConstructor = 0;
return ICS;
}
@@ -3398,7 +3558,17 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType,
// we would be reference-compatible or reference-compatible with
// added qualification. But that wasn't the case, so the reference
// initialization fails.
- return ICS;
+ //
+ // Note that we only want to check address spaces and cvr-qualifiers here.
+ // ObjC GC and lifetime qualifiers aren't important.
+ Qualifiers T1Quals = T1.getQualifiers();
+ Qualifiers T2Quals = T2.getQualifiers();
+ T1Quals.removeObjCGCAttr();
+ T1Quals.removeObjCLifetime();
+ T2Quals.removeObjCGCAttr();
+ T2Quals.removeObjCLifetime();
+ if (!T1Quals.compatiblyIncludes(T2Quals))
+ return ICS;
}
// If at least one of the types is a class type, the types are not
@@ -3429,7 +3599,8 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType,
ICS = TryImplicitConversion(S, Init, T1, SuppressUserConversions,
/*AllowExplicit=*/false,
/*InOverloadResolution=*/false,
- /*CStyle=*/false);
+ /*CStyle=*/false,
+ /*AllowObjCWritebackConversion=*/false);
// Of course, that's still a reference binding.
if (ICS.isStandard()) {
@@ -3438,12 +3609,14 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType,
ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType();
ICS.Standard.BindsToRvalue = true;
ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false;
+ ICS.Standard.ObjCLifetimeConversionBinding = false;
} else if (ICS.isUserDefined()) {
ICS.UserDefined.After.ReferenceBinding = true;
ICS.Standard.IsLvalueReference = !isRValRef;
ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType();
ICS.Standard.BindsToRvalue = true;
ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false;
+ ICS.Standard.ObjCLifetimeConversionBinding = false;
}
return ICS;
@@ -3458,7 +3631,8 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType,
static ImplicitConversionSequence
TryCopyInitialization(Sema &S, Expr *From, QualType ToType,
bool SuppressUserConversions,
- bool InOverloadResolution) {
+ bool InOverloadResolution,
+ bool AllowObjCWritebackConversion) {
if (ToType->isReferenceType())
return TryReferenceInit(S, From, ToType,
/*FIXME:*/From->getLocStart(),
@@ -3469,7 +3643,8 @@ TryCopyInitialization(Sema &S, Expr *From, QualType ToType,
SuppressUserConversions,
/*AllowExplicit=*/false,
InOverloadResolution,
- /*CStyle=*/false);
+ /*CStyle=*/false,
+ AllowObjCWritebackConversion);
}
/// TryObjectArgumentInitialization - Try to initialize the object
@@ -3659,7 +3834,8 @@ TryContextuallyConvertToBool(Sema &S, Expr *From) {
/*SuppressUserConversions=*/false,
/*AllowExplicit=*/true,
/*InOverloadResolution=*/false,
- /*CStyle=*/false);
+ /*CStyle=*/false,
+ /*AllowObjCWritebackConversion=*/false);
}
/// PerformContextuallyConvertToBool - Perform a contextual conversion
@@ -3686,7 +3862,8 @@ TryContextuallyConvertToObjCId(Sema &S, Expr *From) {
/*SuppressUserConversions=*/false,
/*AllowExplicit=*/true,
/*InOverloadResolution=*/false,
- /*CStyle=*/false);
+ /*CStyle=*/false,
+ /*AllowObjCWritebackConversion=*/false);
}
/// PerformContextuallyConvertToObjCId - Perform a contextual conversion
@@ -3980,7 +4157,9 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
Candidate.Conversions[ArgIdx]
= TryCopyInitialization(*this, Args[ArgIdx], ParamType,
SuppressUserConversions,
- /*InOverloadResolution=*/true);
+ /*InOverloadResolution=*/true,
+ /*AllowObjCWritebackConversion=*/
+ getLangOptions().ObjCAutoRefCount);
if (Candidate.Conversions[ArgIdx].isBad()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_conversion;
@@ -4153,7 +4332,9 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
Candidate.Conversions[ArgIdx + 1]
= TryCopyInitialization(*this, Args[ArgIdx], ParamType,
SuppressUserConversions,
- /*InOverloadResolution=*/true);
+ /*InOverloadResolution=*/true,
+ /*AllowObjCWritebackConversion=*/
+ getLangOptions().ObjCAutoRefCount);
if (Candidate.Conversions[ArgIdx + 1].isBad()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_conversion;
@@ -4356,25 +4537,26 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
CK_FunctionToPointerDecay,
&ConversionRef, VK_RValue);
- QualType CallResultType
- = Conversion->getConversionType().getNonLValueExprType(Context);
- if (RequireCompleteType(From->getLocStart(), CallResultType, 0)) {
+ QualType ConversionType = Conversion->getConversionType();
+ if (RequireCompleteType(From->getLocStart(), ConversionType, 0)) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_final_conversion;
return;
}
- ExprValueKind VK = Expr::getValueKindForType(Conversion->getConversionType());
+ ExprValueKind VK = Expr::getValueKindForType(ConversionType);
// Note that it is safe to allocate CallExpr on the stack here because
// there are 0 arguments (i.e., nothing is allocated using ASTContext's
// allocator).
+ QualType CallResultType = ConversionType.getNonLValueExprType(Context);
CallExpr Call(Context, &ConversionFn, 0, 0, CallResultType, VK,
From->getLocStart());
ImplicitConversionSequence ICS =
TryCopyInitialization(*this, &Call, ToType,
/*SuppressUserConversions=*/true,
- /*InOverloadResolution=*/false);
+ /*InOverloadResolution=*/false,
+ /*AllowObjCWritebackConversion=*/false);
switch (ICS.getKind()) {
case ImplicitConversionSequence::StandardConversion:
@@ -4544,7 +4726,9 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
Candidate.Conversions[ArgIdx + 1]
= TryCopyInitialization(*this, Args[ArgIdx], ParamType,
/*SuppressUserConversions=*/false,
- /*InOverloadResolution=*/false);
+ /*InOverloadResolution=*/false,
+ /*AllowObjCWritebackConversion=*/
+ getLangOptions().ObjCAutoRefCount);
if (Candidate.Conversions[ArgIdx + 1].isBad()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_conversion;
@@ -4662,7 +4846,9 @@ void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,
Candidate.Conversions[ArgIdx]
= TryCopyInitialization(*this, Args[ArgIdx], ParamTys[ArgIdx],
ArgIdx == 0 && IsAssignmentOperator,
- /*InOverloadResolution=*/false);
+ /*InOverloadResolution=*/false,
+ /*AllowObjCWritebackConversion=*/
+ getLangOptions().ObjCAutoRefCount);
}
if (Candidate.Conversions[ArgIdx].isBad()) {
Candidate.Viable = false;
@@ -6417,7 +6603,8 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc,
// Best is the best viable function.
if (Best->Function &&
- (Best->Function->isDeleted() || Best->Function->isUnavailable()))
+ (Best->Function->isDeleted() ||
+ S.isFunctionConsideredUnavailable(Best->Function)))
return OR_Deleted;
return OR_Success;
@@ -6619,6 +6806,17 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) {
return;
}
+ if (FromQs.getObjCLifetime() != ToQs.getObjCLifetime()) {
+ S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_ownership)
+ << (unsigned) FnKind << FnDesc
+ << (FromExpr ? FromExpr->getSourceRange() : SourceRange())
+ << FromTy
+ << FromQs.getObjCLifetime() << ToQs.getObjCLifetime()
+ << (unsigned) isObjectArgument << I+1;
+ MaybeEmitInheritedConstructorNote(S, Fn);
+ return;
+ }
+
if (FromQs.getObjCGCAttr() != ToQs.getObjCGCAttr()) {
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_gc)
<< (unsigned) FnKind << FnDesc
@@ -6901,7 +7099,8 @@ void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
FunctionDecl *Fn = Cand->Function;
// Note deleted candidates, but only if they're viable.
- if (Cand->Viable && (Fn->isDeleted() || Fn->isUnavailable())) {
+ if (Cand->Viable && (Fn->isDeleted() ||
+ S.isFunctionConsideredUnavailable(Fn))) {
std::string FnDesc;
OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Fn, FnDesc);
@@ -7152,7 +7351,9 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
= TryCopyInitialization(S, Args[ConvIdx],
Cand->BuiltinTypes.ParamTypes[ConvIdx],
SuppressUserConversions,
- /*InOverloadResolution*/ true);
+ /*InOverloadResolution*/ true,
+ /*AllowObjCWritebackConversion=*/
+ S.getLangOptions().ObjCAutoRefCount);
return;
}
@@ -7163,7 +7364,9 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
Cand->Conversions[ConvIdx]
= TryCopyInitialization(S, Args[ArgIdx], Proto->getArgType(ArgIdx),
SuppressUserConversions,
- /*InOverloadResolution=*/true);
+ /*InOverloadResolution=*/true,
+ /*AllowObjCWritebackConversion=*/
+ S.getLangOptions().ObjCAutoRefCount);
else
Cand->Conversions[ConvIdx].setEllipsis();
}
@@ -7407,8 +7610,8 @@ private:
QualType ResultTy;
if (Context.hasSameUnqualifiedType(TargetFunctionType,
FunDecl->getType()) ||
- IsNoReturnConversion(Context, FunDecl->getType(), TargetFunctionType,
- ResultTy)) {
+ S.IsNoReturnConversion(FunDecl->getType(), TargetFunctionType,
+ ResultTy)) {
Matches.push_back(std::make_pair(CurAccessFunPair,
cast<FunctionDecl>(FunDecl->getCanonicalDecl())));
FoundNonTemplateFunction = true;
@@ -7742,13 +7945,17 @@ static void AddOverloadedCallCandidate(Sema &S,
TemplateArgumentListInfo *ExplicitTemplateArgs,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet &CandidateSet,
- bool PartialOverloading) {
+ bool PartialOverloading,
+ bool KnownValid) {
NamedDecl *Callee = FoundDecl.getDecl();
if (isa<UsingShadowDecl>(Callee))
Callee = cast<UsingShadowDecl>(Callee)->getTargetDecl();
if (FunctionDecl *Func = dyn_cast<FunctionDecl>(Callee)) {
- assert(!ExplicitTemplateArgs && "Explicit template arguments?");
+ if (ExplicitTemplateArgs) {
+ assert(!KnownValid && "Explicit template arguments?");
+ return;
+ }
S.AddOverloadCandidate(Func, FoundDecl, Args, NumArgs, CandidateSet,
false, PartialOverloading);
return;
@@ -7762,9 +7969,7 @@ static void AddOverloadedCallCandidate(Sema &S,
return;
}
- assert(false && "unhandled case in overloaded call candidate");
-
- // do nothing?
+ assert(!KnownValid && "unhandled case in overloaded call candidate");
}
/// \brief Add the overload candidates named by callee and/or found by argument
@@ -7815,7 +8020,7 @@ void Sema::AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE,
E = ULE->decls_end(); I != E; ++I)
AddOverloadedCallCandidate(*this, I.getPair(), ExplicitTemplateArgs,
Args, NumArgs, CandidateSet,
- PartialOverloading);
+ PartialOverloading, /*KnownValid*/ true);
if (ULE->requiresADL())
AddArgumentDependentLookupCandidates(ULE->getName(), /*Operator*/ false,
@@ -7857,13 +8062,15 @@ DiagnoseTwoPhaseLookup(Sema &SemaRef, SourceLocation FnLoc,
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
AddOverloadedCallCandidate(SemaRef, I.getPair(),
ExplicitTemplateArgs, Args, NumArgs,
- Candidates, false);
+ Candidates, false, /*KnownValid*/ false);
OverloadCandidateSet::iterator Best;
- if (Candidates.BestViableFunction(SemaRef, FnLoc, Best) != OR_Success)
+ if (Candidates.BestViableFunction(SemaRef, FnLoc, Best) != OR_Success) {
// No viable functions. Don't bother the user with notes for functions
// which don't work and shouldn't be found anyway.
+ R.clear();
return false;
+ }
// Find the namespaces where ADL would have looked, and suggest
// declaring the function there instead.
@@ -8673,7 +8880,10 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
ResultTy = ResultTy.getNonLValueExprType(Context);
// Build the actual expression node.
- ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl, LLoc);
+ DeclarationNameLoc LocInfo;
+ LocInfo.CXXOperatorName.BeginOpNameLoc = LLoc.getRawEncoding();
+ LocInfo.CXXOperatorName.EndOpNameLoc = RLoc.getRawEncoding();
+ ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl, LLoc, LocInfo);
if (FnExpr.isInvalid())
return ExprError();
@@ -8963,13 +9173,14 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
TheCall->getMethodDecl()->isPure()) {
const CXXMethodDecl *MD = TheCall->getMethodDecl();
- if (isa<CXXThisExpr>(MemExpr->getBase()->IgnoreParenCasts()))
+ if (isa<CXXThisExpr>(MemExpr->getBase()->IgnoreParenCasts())) {
Diag(MemExpr->getLocStart(),
diag::warn_call_to_pure_virtual_member_function_from_ctor_dtor)
<< MD->getDeclName() << isa<CXXDestructorDecl>(CurContext)
<< MD->getParent()->getDeclName();
Diag(MD->getLocStart(), diag::note_previous_decl) << MD->getDeclName();
+ }
}
return MaybeBindToTemporary(TheCall);
}
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index d7c0a543eede..65f431d46075 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -66,8 +66,30 @@ void Sema::ActOnForEachDeclStmt(DeclGroupPtrTy dg) {
// If we have an invalid decl, just return.
if (DG.isNull() || !DG.isSingleDecl()) return;
+ VarDecl *var = cast<VarDecl>(DG.getSingleDecl());
+
// suppress any potential 'unused variable' warning.
- DG.getSingleDecl()->setUsed();
+ var->setUsed();
+
+ // foreach variables are never actually initialized in the way that
+ // the parser came up with.
+ var->setInit(0);
+
+ // In ARC, we don't need to retain the iteration variable of a fast
+ // enumeration loop. Rather than actually trying to catch that
+ // during declaration processing, we remove the consequences here.
+ if (getLangOptions().ObjCAutoRefCount) {
+ QualType type = var->getType();
+
+ // Only do this if we inferred the lifetime. Inferred lifetime
+ // will show up as a local qualifier because explicit lifetime
+ // should have shown up as an AttributedType instead.
+ if (type.getLocalQualifiers().getObjCLifetime() == Qualifiers::OCL_Strong) {
+ // Add 'const' and mark the variable as pseudo-strong.
+ var->setType(type.withConst());
+ var->setARCPseudoStrong(true);
+ }
+ }
}
void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
@@ -114,6 +136,10 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
}
}
} else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) {
+ if (getLangOptions().ObjCAutoRefCount && ME->isDelegateInitCall()) {
+ Diag(Loc, diag::err_arc_unused_init_message) << R1;
+ return;
+ }
const ObjCMethodDecl *MD = ME->getMethodDecl();
if (MD && MD->getAttr<WarnUnusedResultAttr>()) {
Diag(Loc, diag::warn_unused_call) << R1 << R2 << "warn_unused_result";
@@ -951,14 +977,13 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc,
return StmtError(Diag((*DS->decl_begin())->getLocation(),
diag::err_toomany_element_decls));
- Decl *D = DS->getSingleDecl();
- FirstType = cast<ValueDecl>(D)->getType();
+ VarDecl *D = cast<VarDecl>(DS->getSingleDecl());
+ FirstType = D->getType();
// C99 6.8.5p3: The declaration part of a 'for' statement shall only
// declare identifiers for objects having storage class 'auto' or
// 'register'.
- VarDecl *VD = cast<VarDecl>(D);
- if (VD->isLocalVarDecl() && !VD->hasLocalStorage())
- return StmtError(Diag(VD->getLocation(),
+ if (!D->hasLocalStorage())
+ return StmtError(Diag(D->getLocation(),
diag::err_non_variable_decl_in_for));
} else {
Expr *FirstE = cast<Expr>(First);
@@ -1047,6 +1072,13 @@ static bool FinishForRangeVarDecl(Sema &SemaRef, VarDecl *Decl, Expr *Init,
Decl->setTypeSourceInfo(InitTSI);
Decl->setType(InitTSI->getType());
+ // In ARC, infer lifetime.
+ // FIXME: ARC may want to turn this into 'const __unsafe_unretained' if
+ // we're doing the equivalent of fast iteration.
+ if (SemaRef.getLangOptions().ObjCAutoRefCount &&
+ SemaRef.inferObjCARCLifetime(Decl))
+ Decl->setInvalidDecl();
+
SemaRef.AddInitializerToDecl(Decl, Init, /*DirectInit=*/false,
/*TypeMayContainAuto=*/false);
SemaRef.FinalizeDeclaration(Decl);
@@ -1374,6 +1406,9 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
if (LoopVar->isInvalidDecl())
NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
}
+ } else {
+ // The range is implicitly used as a placeholder when it is dependent.
+ RangeVar->setUsed();
}
return Owned(new (Context) CXXForRangeStmt(RangeDS,
@@ -1508,7 +1543,8 @@ ExprResult
Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity,
const VarDecl *NRVOCandidate,
QualType ResultType,
- Expr *Value) {
+ Expr *Value,
+ bool AllowNRVO) {
// C++0x [class.copy]p33:
// When the criteria for elision of a copy operation are met or would
// be met save for the fact that the source object is a function
@@ -1516,7 +1552,8 @@ Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity,
// overload resolution to select the constructor for the copy is first
// performed as if the object were designated by an rvalue.
ExprResult Res = ExprError();
- if (NRVOCandidate || getCopyElisionCandidate(ResultType, Value, true)) {
+ if (AllowNRVO &&
+ (NRVOCandidate || getCopyElisionCandidate(ResultType, Value, true))) {
ImplicitCastExpr AsRvalue(ImplicitCastExpr::OnStack,
Value->getType(), CK_LValueToRValue,
Value, VK_XValue);
@@ -1726,8 +1763,17 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
if (D != diag::ext_return_has_void_expr ||
!getLangOptions().CPlusPlus) {
NamedDecl *CurDecl = getCurFunctionOrMethodDecl();
+
+ int FunctionKind = 0;
+ if (isa<ObjCMethodDecl>(CurDecl))
+ FunctionKind = 1;
+ else if (isa<CXXConstructorDecl>(CurDecl))
+ FunctionKind = 2;
+ else if (isa<CXXDestructorDecl>(CurDecl))
+ FunctionKind = 3;
+
Diag(ReturnLoc, D)
- << CurDecl->getDeclName() << isa<ObjCMethodDecl>(CurDecl)
+ << CurDecl->getDeclName() << FunctionKind
<< RetValExp->getSourceRange();
}
}
@@ -1756,7 +1802,7 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
// overlap restriction of subclause 6.5.16.1 does not apply to the case of
// function return.
- // In C++ the return statement is handled via a copy initialization.
+ // In C++ the return statement is handled via a copy initialization,
// the C version of which boils down to CheckSingleAssignmentConstraints.
NRVOCandidate = getCopyElisionCandidate(FnRetType, RetValExp, false);
InitializedEntity Entity = InitializedEntity::InitializeResult(ReturnLoc,
@@ -1797,7 +1843,7 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
if (getLangOptions().CPlusPlus && FnRetType->isRecordType() &&
!CurContext->isDependentContext())
FunctionScopes.back()->Returns.push_back(Result);
-
+
return Owned(Result);
}
@@ -1955,7 +2001,7 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple,
llvm::StringRef Clobber = Literal->getString();
- if (!Context.Target.isValidGCCRegisterName(Clobber))
+ if (!Context.Target.isValidClobber(Clobber))
return StmtError(Diag(Literal->getLocStart(),
diag::err_asm_unknown_register_name) << Clobber);
}
@@ -2179,6 +2225,12 @@ Sema::ActOnCXXCatchBlock(SourceLocation CatchLoc, Decl *ExDecl,
HandlerBlock));
}
+StmtResult
+Sema::ActOnObjCAutoreleasePoolStmt(SourceLocation AtLoc, Stmt *Body) {
+ getCurFunction()->setHasBranchProtectedScope();
+ return Owned(new (Context) ObjCAutoreleasePoolStmt(AtLoc, Body));
+}
+
namespace {
class TypeWithHandler {
@@ -2309,4 +2361,3 @@ Sema::ActOnSEHFinallyBlock(SourceLocation Loc,
assert(Block);
return Owned(SEHFinallyStmt::Create(Context,Loc,Block));
}
-
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 5d4caacd8124..3ac190e1d4c8 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -294,26 +294,31 @@ void Sema::LookupTemplateName(LookupResult &Found,
if (Found.empty() && !isDependent) {
// If we did not find any names, attempt to correct any typos.
DeclarationName Name = Found.getLookupName();
- if (DeclarationName Corrected = CorrectTypo(Found, S, &SS, LookupCtx,
- false, CTC_CXXCasts)) {
+ Found.clear();
+ if (TypoCorrection Corrected = CorrectTypo(Found.getLookupNameInfo(),
+ Found.getLookupKind(), S, &SS,
+ LookupCtx, false,
+ CTC_CXXCasts)) {
+ Found.setLookupName(Corrected.getCorrection());
+ if (Corrected.getCorrectionDecl())
+ Found.addDecl(Corrected.getCorrectionDecl());
FilterAcceptableTemplateNames(Found);
if (!Found.empty()) {
+ std::string CorrectedStr(Corrected.getAsString(getLangOptions()));
+ std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOptions()));
if (LookupCtx)
Diag(Found.getNameLoc(), diag::err_no_member_template_suggest)
- << Name << LookupCtx << Found.getLookupName() << SS.getRange()
- << FixItHint::CreateReplacement(Found.getNameLoc(),
- Found.getLookupName().getAsString());
+ << Name << LookupCtx << CorrectedQuotedStr << SS.getRange()
+ << FixItHint::CreateReplacement(Found.getNameLoc(), CorrectedStr);
else
Diag(Found.getNameLoc(), diag::err_no_template_suggest)
- << Name << Found.getLookupName()
- << FixItHint::CreateReplacement(Found.getNameLoc(),
- Found.getLookupName().getAsString());
+ << Name << CorrectedQuotedStr
+ << FixItHint::CreateReplacement(Found.getNameLoc(), CorrectedStr);
if (TemplateDecl *Template = Found.getAsSingle<TemplateDecl>())
Diag(Template->getLocation(), diag::note_previous_decl)
- << Template->getDeclName();
+ << CorrectedQuotedStr;
}
} else {
- Found.clear();
Found.setLookupName(Name);
}
}
@@ -1856,7 +1861,8 @@ void Sema::NoteAllFoundTemplates(TemplateName Name) {
QualType Sema::CheckTemplateIdType(TemplateName Name,
SourceLocation TemplateLoc,
TemplateArgumentListInfo &TemplateArgs) {
- DependentTemplateName *DTN = Name.getAsDependentTemplateName();
+ DependentTemplateName *DTN
+ = Name.getUnderlying().getAsDependentTemplateName();
if (DTN && DTN->isIdentifier())
// When building a template-id where the template-name is dependent,
// assume the template is a type template. Either our assumption is
@@ -1892,6 +1898,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
QualType CanonType;
+ bool InstantiationDependent = false;
if (TypeAliasTemplateDecl *AliasTemplate
= dyn_cast<TypeAliasTemplateDecl>(Template)) {
// Find the canonical type for this type alias template specialization.
@@ -1917,7 +1924,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
return QualType();
} else if (Name.isDependent() ||
TemplateSpecializationType::anyDependentTemplateArguments(
- TemplateArgs)) {
+ TemplateArgs, InstantiationDependent)) {
// This class template specialization is a dependent
// type. Therefore, its canonical type is another class template
// specialization type that contains all of the converted
@@ -2357,8 +2364,20 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
return true;
// Add the converted template type argument.
- Converted.push_back(
- TemplateArgument(Context.getCanonicalType(Arg.getAsType())));
+ QualType ArgType = Context.getCanonicalType(Arg.getAsType());
+
+ // Objective-C ARC:
+ // If an explicitly-specified template argument type is a lifetime type
+ // with no lifetime qualifier, the __strong lifetime qualifier is inferred.
+ if (getLangOptions().ObjCAutoRefCount &&
+ ArgType->isObjCLifetimeType() &&
+ !ArgType.getObjCLifetime()) {
+ Qualifiers Qs;
+ Qs.setObjCLifetime(Qualifiers::OCL_Strong);
+ ArgType = Context.getQualifiedType(ArgType, Qs);
+ }
+
+ Converted.push_back(TemplateArgument(ArgType));
return false;
}
@@ -2912,16 +2931,6 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
// arguments, just break out now and we'll fill in the argument pack below.
if ((*Param)->isTemplateParameterPack())
break;
-
- // If our template is a template template parameter that hasn't acquired
- // its proper context yet (e.g., because we're using the template template
- // parameter in the signature of a function template, before we've built
- // the function template itself), don't attempt substitution of default
- // template arguments at this point: we don't have enough context to
- // do it properly.
- if (isTemplateTemplateParameter &&
- Template->getDeclContext()->isTranslationUnit())
- break;
// We have a default template argument that we will use.
TemplateArgumentLoc Arg;
@@ -3307,8 +3316,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
QualType ArgType = Arg->getType();
// See through any implicit casts we added to fix the type.
- while (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(Arg))
- Arg = Cast->getSubExpr();
+ Arg = Arg->IgnoreImpCasts();
// C++ [temp.arg.nontype]p1:
//
@@ -3321,7 +3329,6 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
// expressed as & id-expression where the & is optional if
// the name refers to a function or array, or if the
// corresponding template-parameter is a reference; or
- DeclRefExpr *DRE = 0;
// In C++98/03 mode, give an extension warning on any extra parentheses.
// See http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#773
@@ -3337,29 +3344,30 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
Arg = Parens->getSubExpr();
}
+ while (SubstNonTypeTemplateParmExpr *subst =
+ dyn_cast<SubstNonTypeTemplateParmExpr>(Arg))
+ Arg = subst->getReplacement()->IgnoreImpCasts();
+
bool AddressTaken = false;
SourceLocation AddrOpLoc;
if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(Arg)) {
if (UnOp->getOpcode() == UO_AddrOf) {
- // Support &__uuidof(class_with_uuid) as a non-type template argument.
- // Very common in Microsoft COM headers.
- if (S.getLangOptions().Microsoft &&
- isa<CXXUuidofExpr>(UnOp->getSubExpr())) {
- Converted = TemplateArgument(ArgIn);
- return false;
- }
-
- DRE = dyn_cast<DeclRefExpr>(UnOp->getSubExpr());
+ Arg = UnOp->getSubExpr();
AddressTaken = true;
AddrOpLoc = UnOp->getOperatorLoc();
}
- } else {
- if (S.getLangOptions().Microsoft && isa<CXXUuidofExpr>(Arg)) {
- Converted = TemplateArgument(ArgIn);
- return false;
- }
- DRE = dyn_cast<DeclRefExpr>(Arg);
}
+
+ if (S.getLangOptions().Microsoft && isa<CXXUuidofExpr>(Arg)) {
+ Converted = TemplateArgument(ArgIn);
+ return false;
+ }
+
+ while (SubstNonTypeTemplateParmExpr *subst =
+ dyn_cast<SubstNonTypeTemplateParmExpr>(Arg))
+ Arg = subst->getReplacement()->IgnoreImpCasts();
+
+ DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Arg);
if (!DRE) {
S.Diag(Arg->getLocStart(), diag::err_template_arg_not_decl_ref)
<< Arg->getSourceRange();
@@ -3513,9 +3521,11 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
return true;
}
+ bool ObjCLifetimeConversion;
if (ParamType->isPointerType() &&
!ParamType->getAs<PointerType>()->getPointeeType()->isFunctionType() &&
- S.IsQualificationConversion(ArgType, ParamType, false)) {
+ S.IsQualificationConversion(ArgType, ParamType, false,
+ ObjCLifetimeConversion)) {
// For pointer-to-object types, qualification conversions are
// permitted.
} else {
@@ -3552,10 +3562,10 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
// We can't perform this conversion or binding.
if (ParamType->isReferenceType())
S.Diag(Arg->getLocStart(), diag::err_template_arg_no_ref_bind)
- << ParamType << Arg->getType() << Arg->getSourceRange();
+ << ParamType << ArgIn->getType() << Arg->getSourceRange();
else
S.Diag(Arg->getLocStart(), diag::err_template_arg_not_convertible)
- << Arg->getType() << ParamType << Arg->getSourceRange();
+ << ArgIn->getType() << ParamType << Arg->getSourceRange();
S.Diag(Param->getLocation(), diag::note_template_param_here);
return true;
}
@@ -3599,6 +3609,10 @@ bool Sema::CheckTemplateArgumentPointerToMember(Expr *Arg,
Arg = Parens->getSubExpr();
}
+ while (SubstNonTypeTemplateParmExpr *subst =
+ dyn_cast<SubstNonTypeTemplateParmExpr>(Arg))
+ Arg = subst->getReplacement()->IgnoreImpCasts();
+
// A pointer-to-member constant written &Class::member.
if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(Arg)) {
if (UnOp->getOpcode() == UO_AddrOf) {
@@ -3875,8 +3889,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
return Owned(Arg);
}
+ bool ObjCLifetimeConversion;
if (IsQualificationConversion(ArgType, ParamType.getNonReferenceType(),
- false)) {
+ false, ObjCLifetimeConversion)) {
Arg = ImpCastExprToType(Arg, ParamType, CK_NoOp, CastCategory(Arg)).take();
} else if (!Context.hasSameUnqualifiedType(ArgType,
ParamType.getNonReferenceType())) {
@@ -3943,9 +3958,11 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// member, qualification conversions (4.4) are applied.
assert(ParamType->isMemberPointerType() && "Only pointers to members remain");
+ bool ObjCLifetimeConversion;
if (Context.hasSameUnqualifiedType(ParamType, ArgType)) {
// Types match exactly: nothing more to do here.
- } else if (IsQualificationConversion(ArgType, ParamType, false)) {
+ } else if (IsQualificationConversion(ArgType, ParamType, false,
+ ObjCLifetimeConversion)) {
Arg = ImpCastExprToType(Arg, ParamType, CK_NoOp, CastCategory(Arg)).take();
} else {
// We can't perform this conversion.
@@ -4053,8 +4070,10 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
// We might need to perform a trailing qualification conversion, since
// the element type on the parameter could be more qualified than the
// element type in the expression we constructed.
+ bool ObjCLifetimeConversion;
if (IsQualificationConversion(((Expr*) RefExpr.get())->getType(),
- ParamType.getUnqualifiedType(), false))
+ ParamType.getUnqualifiedType(), false,
+ ObjCLifetimeConversion))
RefExpr = ImpCastExprToType(RefExpr.take(), ParamType.getUnqualifiedType(), CK_NoOp);
assert(!RefExpr.isInvalid() &&
@@ -4818,10 +4837,12 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
Converted))
return true;
+ bool InstantiationDependent;
if (!Name.isDependent() &&
!TemplateSpecializationType::anyDependentTemplateArguments(
TemplateArgs.getArgumentArray(),
- TemplateArgs.size())) {
+ TemplateArgs.size(),
+ InstantiationDependent)) {
Diag(TemplateNameLoc, diag::err_partial_spec_fully_specialized)
<< ClassTemplate->getDeclName();
isPartialSpecialization = false;
@@ -5346,7 +5367,7 @@ Sema::CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD,
/// explicitly provided as in, e.g., \c void sort<>(char*, char*);
/// as it anyway contains info on the angle brackets locations.
///
-/// \param PrevDecl the set of declarations that may be specialized by
+/// \param Previous the set of declarations that may be specialized by
/// this function specialization.
bool
Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
@@ -5410,13 +5431,12 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
FunctionTemplateSpecializationInfo *SpecInfo
= Specialization->getTemplateSpecializationInfo();
assert(SpecInfo && "Function template specialization info missing?");
- {
- // Note: do not overwrite location info if previous template
- // specialization kind was explicit.
- TemplateSpecializationKind TSK = SpecInfo->getTemplateSpecializationKind();
- if (TSK == TSK_Undeclared || TSK == TSK_ImplicitInstantiation)
- Specialization->setLocation(FD->getLocation());
- }
+
+ // Note: do not overwrite location info if previous template
+ // specialization kind was explicit.
+ TemplateSpecializationKind TSK = SpecInfo->getTemplateSpecializationKind();
+ if (TSK == TSK_Undeclared || TSK == TSK_ImplicitInstantiation)
+ Specialization->setLocation(FD->getLocation());
// FIXME: Check if the prior specialization has a point of instantiation.
// If so, we have run afoul of .
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 7d0ce8b2e71d..dcb4ff286060 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -12,7 +12,6 @@
#include "clang/Sema/Sema.h"
#include "clang/Sema/DeclSpec.h"
-#include "clang/Sema/SemaDiagnostic.h" // FIXME: temporary!
#include "clang/Sema/Template.h"
#include "clang/Sema/TemplateDeduction.h"
#include "clang/AST/ASTContext.h"
@@ -820,6 +819,11 @@ static bool hasInconsistentOrSupersetQualifiersOf(QualType ParamType,
ParamQs.hasAddressSpace())
return true;
+ // Mismatched (but not missing) Objective-C lifetime qualifiers.
+ if (ParamQs.getObjCLifetime() != ArgQs.getObjCLifetime() &&
+ ParamQs.hasObjCLifetime())
+ return true;
+
// CVR qualifier superset.
return (ParamQs.getCVRQualifiers() != ArgQs.getCVRQualifiers()) &&
((ParamQs.getCVRQualifiers() | ArgQs.getCVRQualifiers())
@@ -1010,6 +1014,17 @@ DeduceTemplateArguments(Sema &S,
DeducedQs.removeObjCGCAttr();
if (ParamQs.hasAddressSpace())
DeducedQs.removeAddressSpace();
+ if (ParamQs.hasObjCLifetime())
+ DeducedQs.removeObjCLifetime();
+
+ // Objective-C ARC:
+ // If template deduction would produce an argument type with lifetime type
+ // but no lifetime qualifier, the __strong lifetime qualifier is inferred.
+ if (S.getLangOptions().ObjCAutoRefCount &&
+ DeducedType->isObjCLifetimeType() &&
+ !DeducedQs.hasObjCLifetime())
+ DeducedQs.setObjCLifetime(Qualifiers::OCL_Strong);
+
DeducedType = S.Context.getQualifiedType(DeducedType.getUnqualifiedType(),
DeducedQs);
@@ -1054,10 +1069,39 @@ DeduceTemplateArguments(Sema &S,
}
switch (Param->getTypeClass()) {
- // No deduction possible for these types
+ // Non-canonical types cannot appear here.
+#define NON_CANONICAL_TYPE(Class, Base) \
+ case Type::Class: llvm_unreachable("deducing non-canonical type: " #Class);
+#define TYPE(Class, Base)
+#include "clang/AST/TypeNodes.def"
+
+ case Type::TemplateTypeParm:
+ case Type::SubstTemplateTypeParmPack:
+ llvm_unreachable("Type nodes handled above");
+
+ // These types cannot be used in templates or cannot be dependent, so
+ // deduction always fails.
case Type::Builtin:
+ case Type::VariableArray:
+ case Type::Vector:
+ case Type::FunctionNoProto:
+ case Type::Record:
+ case Type::Enum:
+ case Type::ObjCObject:
+ case Type::ObjCInterface:
+ case Type::ObjCObjectPointer:
return Sema::TDK_NonDeducedMismatch;
+ // _Complex T [placeholder extension]
+ case Type::Complex:
+ if (const ComplexType *ComplexArg = Arg->getAs<ComplexType>())
+ return DeduceTemplateArguments(S, TemplateParams,
+ cast<ComplexType>(Param)->getElementType(),
+ ComplexArg->getElementType(),
+ Info, Deduced, TDF);
+
+ return Sema::TDK_NonDeducedMismatch;
+
// T *
case Type::Pointer: {
QualType PointeeType;
@@ -1361,17 +1405,107 @@ DeduceTemplateArguments(Sema &S,
Deduced, 0);
}
+ // (clang extension)
+ //
+ // T __attribute__(((ext_vector_type(<integral constant>))))
+ case Type::ExtVector: {
+ const ExtVectorType *VectorParam = cast<ExtVectorType>(Param);
+ if (const ExtVectorType *VectorArg = dyn_cast<ExtVectorType>(Arg)) {
+ // Make sure that the vectors have the same number of elements.
+ if (VectorParam->getNumElements() != VectorArg->getNumElements())
+ return Sema::TDK_NonDeducedMismatch;
+
+ // Perform deduction on the element types.
+ return DeduceTemplateArguments(S, TemplateParams,
+ VectorParam->getElementType(),
+ VectorArg->getElementType(),
+ Info, Deduced,
+ TDF);
+ }
+
+ if (const DependentSizedExtVectorType *VectorArg
+ = dyn_cast<DependentSizedExtVectorType>(Arg)) {
+ // We can't check the number of elements, since the argument has a
+ // dependent number of elements. This can only occur during partial
+ // ordering.
+
+ // Perform deduction on the element types.
+ return DeduceTemplateArguments(S, TemplateParams,
+ VectorParam->getElementType(),
+ VectorArg->getElementType(),
+ Info, Deduced,
+ TDF);
+ }
+
+ return Sema::TDK_NonDeducedMismatch;
+ }
+
+ // (clang extension)
+ //
+ // T __attribute__(((ext_vector_type(N))))
+ case Type::DependentSizedExtVector: {
+ const DependentSizedExtVectorType *VectorParam
+ = cast<DependentSizedExtVectorType>(Param);
+
+ if (const ExtVectorType *VectorArg = dyn_cast<ExtVectorType>(Arg)) {
+ // Perform deduction on the element types.
+ if (Sema::TemplateDeductionResult Result
+ = DeduceTemplateArguments(S, TemplateParams,
+ VectorParam->getElementType(),
+ VectorArg->getElementType(),
+ Info, Deduced,
+ TDF))
+ return Result;
+
+ // Perform deduction on the vector size, if we can.
+ NonTypeTemplateParmDecl *NTTP
+ = getDeducedParameterFromExpr(VectorParam->getSizeExpr());
+ if (!NTTP)
+ return Sema::TDK_Success;
+
+ llvm::APSInt ArgSize(S.Context.getTypeSize(S.Context.IntTy), false);
+ ArgSize = VectorArg->getNumElements();
+ return DeduceNonTypeTemplateArgument(S, NTTP, ArgSize, S.Context.IntTy,
+ false, Info, Deduced);
+ }
+
+ if (const DependentSizedExtVectorType *VectorArg
+ = dyn_cast<DependentSizedExtVectorType>(Arg)) {
+ // Perform deduction on the element types.
+ if (Sema::TemplateDeductionResult Result
+ = DeduceTemplateArguments(S, TemplateParams,
+ VectorParam->getElementType(),
+ VectorArg->getElementType(),
+ Info, Deduced,
+ TDF))
+ return Result;
+
+ // Perform deduction on the vector size, if we can.
+ NonTypeTemplateParmDecl *NTTP
+ = getDeducedParameterFromExpr(VectorParam->getSizeExpr());
+ if (!NTTP)
+ return Sema::TDK_Success;
+
+ return DeduceNonTypeTemplateArgument(S, NTTP, VectorArg->getSizeExpr(),
+ Info, Deduced);
+ }
+
+ return Sema::TDK_NonDeducedMismatch;
+ }
+
case Type::TypeOfExpr:
case Type::TypeOf:
case Type::DependentName:
+ case Type::UnresolvedUsing:
+ case Type::Decltype:
+ case Type::UnaryTransform:
+ case Type::Auto:
+ case Type::DependentTemplateSpecialization:
+ case Type::PackExpansion:
// No template argument deduction for these types
return Sema::TDK_Success;
-
- default:
- break;
}
- // FIXME: Many more cases to go (to go).
return Sema::TDK_Success;
}
@@ -2189,15 +2323,108 @@ Sema::SubstituteExplicitTemplateArguments(
return TDK_Success;
}
+/// \brief Check whether the deduced argument type for a call to a function
+/// template matches the actual argument type per C++ [temp.deduct.call]p4.
+static bool
+CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg,
+ QualType DeducedA) {
+ ASTContext &Context = S.Context;
+
+ QualType A = OriginalArg.OriginalArgType;
+ QualType OriginalParamType = OriginalArg.OriginalParamType;
+
+ // Check for type equality (top-level cv-qualifiers are ignored).
+ if (Context.hasSameUnqualifiedType(A, DeducedA))
+ return false;
+
+ // Strip off references on the argument types; they aren't needed for
+ // the following checks.
+ if (const ReferenceType *DeducedARef = DeducedA->getAs<ReferenceType>())
+ DeducedA = DeducedARef->getPointeeType();
+ if (const ReferenceType *ARef = A->getAs<ReferenceType>())
+ A = ARef->getPointeeType();
+
+ // C++ [temp.deduct.call]p4:
+ // [...] However, there are three cases that allow a difference:
+ // - If the original P is a reference type, the deduced A (i.e., the
+ // type referred to by the reference) can be more cv-qualified than
+ // the transformed A.
+ if (const ReferenceType *OriginalParamRef
+ = OriginalParamType->getAs<ReferenceType>()) {
+ // We don't want to keep the reference around any more.
+ OriginalParamType = OriginalParamRef->getPointeeType();
+
+ Qualifiers AQuals = A.getQualifiers();
+ Qualifiers DeducedAQuals = DeducedA.getQualifiers();
+ if (AQuals == DeducedAQuals) {
+ // Qualifiers match; there's nothing to do.
+ } else if (!DeducedAQuals.compatiblyIncludes(AQuals)) {
+ return true;
+ } else {
+ // Qualifiers are compatible, so have the argument type adopt the
+ // deduced argument type's qualifiers as if we had performed the
+ // qualification conversion.
+ A = Context.getQualifiedType(A.getUnqualifiedType(), DeducedAQuals);
+ }
+ }
+
+ // - The transformed A can be another pointer or pointer to member
+ // type that can be converted to the deduced A via a qualification
+ // conversion.
+ //
+ // Also allow conversions which merely strip [[noreturn]] from function types
+ // (recursively) as an extension.
+ // FIXME: Currently, this doesn't place nicely with qualfication conversions.
+ bool ObjCLifetimeConversion = false;
+ QualType ResultTy;
+ if ((A->isAnyPointerType() || A->isMemberPointerType()) &&
+ (S.IsQualificationConversion(A, DeducedA, false,
+ ObjCLifetimeConversion) ||
+ S.IsNoReturnConversion(A, DeducedA, ResultTy)))
+ return false;
+
+
+ // - If P is a class and P has the form simple-template-id, then the
+ // transformed A can be a derived class of the deduced A. [...]
+ // [...] Likewise, if P is a pointer to a class of the form
+ // simple-template-id, the transformed A can be a pointer to a
+ // derived class pointed to by the deduced A.
+ if (const PointerType *OriginalParamPtr
+ = OriginalParamType->getAs<PointerType>()) {
+ if (const PointerType *DeducedAPtr = DeducedA->getAs<PointerType>()) {
+ if (const PointerType *APtr = A->getAs<PointerType>()) {
+ if (A->getPointeeType()->isRecordType()) {
+ OriginalParamType = OriginalParamPtr->getPointeeType();
+ DeducedA = DeducedAPtr->getPointeeType();
+ A = APtr->getPointeeType();
+ }
+ }
+ }
+ }
+
+ if (Context.hasSameUnqualifiedType(A, DeducedA))
+ return false;
+
+ if (A->isRecordType() && isSimpleTemplateIdType(OriginalParamType) &&
+ S.IsDerivedFrom(A, DeducedA))
+ return false;
+
+ return true;
+}
+
/// \brief Finish template argument deduction for a function template,
/// checking the deduced template arguments for completeness and forming
/// the function template specialization.
+///
+/// \param OriginalCallArgs If non-NULL, the original call arguments against
+/// which the deduced argument types should be compared.
Sema::TemplateDeductionResult
Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
unsigned NumExplicitlySpecified,
FunctionDecl *&Specialization,
- TemplateDeductionInfo &Info) {
+ TemplateDeductionInfo &Info,
+ llvm::SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs) {
TemplateParameterList *TemplateParams
= FunctionTemplate->getTemplateParameters();
@@ -2351,6 +2578,24 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
!Trap.hasErrorOccurred())
Info.take();
+ if (OriginalCallArgs) {
+ // C++ [temp.deduct.call]p4:
+ // In general, the deduction process attempts to find template argument
+ // values that will make the deduced A identical to A (after the type A
+ // is transformed as described above). [...]
+ for (unsigned I = 0, N = OriginalCallArgs->size(); I != N; ++I) {
+ OriginalCallArg OriginalArg = (*OriginalCallArgs)[I];
+ unsigned ParamIdx = OriginalArg.ArgIdx;
+
+ if (ParamIdx >= Specialization->getNumParams())
+ continue;
+
+ QualType DeducedA = Specialization->getParamDecl(ParamIdx)->getType();
+ if (CheckOriginalCallArgDeduction(*this, OriginalArg, DeducedA))
+ return Sema::TDK_SubstitutionFailure;
+ }
+ }
+
// There may have been an error that did not prevent us from constructing a
// declaration. Mark the declaration invalid and return with a substitution
// failure.
@@ -2594,6 +2839,10 @@ static bool AdjustFunctionParmAndArgTypesForDeduction(Sema &S,
return false;
}
+static bool hasDeducibleTemplateParameters(Sema &S,
+ FunctionTemplateDecl *FunctionTemplate,
+ QualType T);
+
/// \brief Perform template argument deduction from a function call
/// (C++ [temp.deduct.call]).
///
@@ -2675,10 +2924,12 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
// Deduce template arguments from the function parameters.
Deduced.resize(TemplateParams->size());
unsigned ArgIdx = 0;
+ llvm::SmallVector<OriginalCallArg, 4> OriginalCallArgs;
for (unsigned ParamIdx = 0, NumParams = ParamTypes.size();
ParamIdx != NumParams; ++ParamIdx) {
- QualType ParamType = ParamTypes[ParamIdx];
-
+ QualType OrigParamType = ParamTypes[ParamIdx];
+ QualType ParamType = OrigParamType;
+
const PackExpansionType *ParamExpansion
= dyn_cast<PackExpansionType>(ParamType);
if (!ParamExpansion) {
@@ -2688,20 +2939,25 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
Expr *Arg = Args[ArgIdx++];
QualType ArgType = Arg->getType();
+
unsigned TDF = 0;
if (AdjustFunctionParmAndArgTypesForDeduction(*this, TemplateParams,
ParamType, ArgType, Arg,
TDF))
continue;
+ // Keep track of the argument type and corresponding parameter index,
+ // so we can check for compatibility between the deduced A and A.
+ if (hasDeducibleTemplateParameters(*this, FunctionTemplate, ParamType))
+ OriginalCallArgs.push_back(OriginalCallArg(OrigParamType, ArgIdx-1,
+ ArgType));
+
if (TemplateDeductionResult Result
= ::DeduceTemplateArguments(*this, TemplateParams,
ParamType, ArgType, Info, Deduced,
TDF))
return Result;
- // FIXME: we need to check that the deduced A is the same as A,
- // modulo the various allowed differences.
continue;
}
@@ -2747,9 +3003,11 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
for (; ArgIdx < NumArgs; ++ArgIdx) {
HasAnyArguments = true;
- ParamType = ParamPattern;
+ QualType OrigParamType = ParamPattern;
+ ParamType = OrigParamType;
Expr *Arg = Args[ArgIdx];
QualType ArgType = Arg->getType();
+
unsigned TDF = 0;
if (AdjustFunctionParmAndArgTypesForDeduction(*this, TemplateParams,
ParamType, ArgType, Arg,
@@ -2760,6 +3018,12 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
break;
}
+ // Keep track of the argument type and corresponding argument index,
+ // so we can check for compatibility between the deduced A and A.
+ if (hasDeducibleTemplateParameters(*this, FunctionTemplate, ParamType))
+ OriginalCallArgs.push_back(OriginalCallArg(OrigParamType, ArgIdx,
+ ArgType));
+
if (TemplateDeductionResult Result
= ::DeduceTemplateArguments(*this, TemplateParams,
ParamType, ArgType, Info, Deduced,
@@ -2792,7 +3056,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
return FinishTemplateArgumentDeduction(FunctionTemplate, Deduced,
NumExplicitlySpecified,
- Specialization, Info);
+ Specialization, Info, &OriginalCallArgs);
}
/// \brief Deduce template arguments when taking the address of a function
@@ -2969,9 +3233,6 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
P, A, Info, Deduced, TDF))
return Result;
- // FIXME: we need to check that the deduced A is the same as A,
- // modulo the various allowed differences.
-
// Finish template argument deduction.
LocalInstantiationScope InstScope(*this);
FunctionDecl *Spec = 0;
@@ -3099,8 +3360,19 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *Init,
QualType DeducedType = Deduced[0].getAsType();
if (DeducedType.isNull())
return false;
-
+
Result = SubstituteAutoTransform(*this, DeducedType).TransformType(Type);
+
+ // Check that the deduced argument type is compatible with the original
+ // argument type per C++ [temp.deduct.call]p4.
+ if (Result &&
+ CheckOriginalCallArgDeduction(*this,
+ Sema::OriginalCallArg(FuncParam,0,InitType),
+ Result->getType())) {
+ Result = 0;
+ return false;
+ }
+
return true;
}
@@ -3227,8 +3499,6 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
case TPOC_Other:
// - In other contexts (14.6.6.2) the function template's function type
// is used.
- // FIXME: Don't we actually want to perform the adjustments on the parameter
- // types?
if (DeduceTemplateArguments(S, TemplateParams, FD2->getType(),
FD1->getType(), Info, Deduced, TDF_None,
/*PartialOrdering=*/true, RefParamComparisons))
@@ -4010,3 +4280,23 @@ Sema::MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate,
::MarkUsedTemplateParameters(*this, Function->getParamDecl(I)->getType(),
true, TemplateParams->getDepth(), Deduced);
}
+
+bool hasDeducibleTemplateParameters(Sema &S,
+ FunctionTemplateDecl *FunctionTemplate,
+ QualType T) {
+ if (!T->isDependentType())
+ return false;
+
+ TemplateParameterList *TemplateParams
+ = FunctionTemplate->getTemplateParameters();
+ llvm::SmallVector<bool, 4> Deduced;
+ Deduced.resize(TemplateParams->size());
+ ::MarkUsedTemplateParameters(S, T, true, TemplateParams->getDepth(),
+ Deduced);
+
+ for (unsigned I = 0, N = Deduced.size(); I != N; ++I)
+ if (Deduced[I])
+ return true;
+
+ return false;
+}
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 3c1964175b10..1988f1445814 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -62,8 +62,20 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D,
if (!Ctx) {
Ctx = D->getDeclContext();
- assert((!D->isTemplateParameter() || !Ctx->isTranslationUnit()) &&
- "Template parameter doesn't have its context yet!");
+ // If we have a template template parameter with translation unit context,
+ // then we're performing substitution into a default template argument of
+ // this template template parameter before we've constructed the template
+ // that will own this template template parameter. In this case, we
+ // use empty template parameter lists for all of the outer templates
+ // to avoid performing any substitutions.
+ if (Ctx->isTranslationUnit()) {
+ if (TemplateTemplateParmDecl *TTP
+ = dyn_cast<TemplateTemplateParmDecl>(D)) {
+ for (unsigned I = 0, N = TTP->getDepth() + 1; I != N; ++I)
+ Result.addOuterTemplateArguments(0, 0);
+ return Result;
+ }
+ }
}
while (!Ctx->isFileContext()) {
@@ -788,6 +800,11 @@ namespace {
getSema().CallsUndergoingInstantiation.pop_back();
return move(Result);
}
+
+ private:
+ ExprResult transformNonTypeTemplateParmRef(NonTypeTemplateParmDecl *parm,
+ SourceLocation loc,
+ const TemplateArgument &arg);
};
}
@@ -795,7 +812,7 @@ bool TemplateInstantiator::AlreadyTransformed(QualType T) {
if (T.isNull())
return true;
- if (T->isDependentType() || T->isVariablyModifiedType())
+ if (T->isInstantiationDependentType() || T->isVariablyModifiedType())
return false;
getSema().MarkDeclarationsReferencedInType(Loc, T);
@@ -980,13 +997,14 @@ TemplateName TemplateInstantiator::TransformTemplateName(CXXScopeSpec &SS,
TemplateName Template = Arg.getAsTemplate();
assert(!Template.isNull() && "Null template template argument");
-
+
// We don't ever want to substitute for a qualified template name, since
// the qualifier is handled separately. So, look through the qualified
// template name to its underlying declaration.
if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
Template = TemplateName(QTN->getTemplateDecl());
-
+
+ Template = getSema().Context.getSubstTemplateTemplateParm(TTP, Template);
return Template;
}
}
@@ -1065,46 +1083,65 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E,
Arg = Arg.pack_begin()[getSema().ArgumentPackSubstitutionIndex];
}
+ return transformNonTypeTemplateParmRef(NTTP, E->getLocation(), Arg);
+}
+
+ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef(
+ NonTypeTemplateParmDecl *parm,
+ SourceLocation loc,
+ const TemplateArgument &arg) {
+ ExprResult result;
+ QualType type;
+
// The template argument itself might be an expression, in which
// case we just return that expression.
- if (Arg.getKind() == TemplateArgument::Expression)
- return SemaRef.Owned(Arg.getAsExpr());
+ if (arg.getKind() == TemplateArgument::Expression) {
+ Expr *argExpr = arg.getAsExpr();
+ result = SemaRef.Owned(argExpr);
+ type = argExpr->getType();
- if (Arg.getKind() == TemplateArgument::Declaration) {
- ValueDecl *VD = cast<ValueDecl>(Arg.getAsDecl());
+ } else if (arg.getKind() == TemplateArgument::Declaration) {
+ ValueDecl *VD = cast<ValueDecl>(arg.getAsDecl());
// Find the instantiation of the template argument. This is
// required for nested templates.
VD = cast_or_null<ValueDecl>(
- getSema().FindInstantiatedDecl(E->getLocation(),
- VD, TemplateArgs));
+ getSema().FindInstantiatedDecl(loc, VD, TemplateArgs));
if (!VD)
return ExprError();
// Derive the type we want the substituted decl to have. This had
// better be non-dependent, or these checks will have serious problems.
- QualType TargetType;
- if (NTTP->isExpandedParameterPack())
- TargetType = NTTP->getExpansionType(
- getSema().ArgumentPackSubstitutionIndex);
- else if (NTTP->isParameterPack() &&
- isa<PackExpansionType>(NTTP->getType())) {
- TargetType = SemaRef.SubstType(
- cast<PackExpansionType>(NTTP->getType())->getPattern(),
- TemplateArgs, E->getLocation(),
- NTTP->getDeclName());
- } else
- TargetType = SemaRef.SubstType(NTTP->getType(), TemplateArgs,
- E->getLocation(), NTTP->getDeclName());
- assert(!TargetType.isNull() && "type substitution failed for param type");
- assert(!TargetType->isDependentType() && "param type still dependent");
- return SemaRef.BuildExpressionFromDeclTemplateArgument(Arg,
- TargetType,
- E->getLocation());
+ if (parm->isExpandedParameterPack()) {
+ type = parm->getExpansionType(SemaRef.ArgumentPackSubstitutionIndex);
+ } else if (parm->isParameterPack() &&
+ isa<PackExpansionType>(parm->getType())) {
+ type = SemaRef.SubstType(
+ cast<PackExpansionType>(parm->getType())->getPattern(),
+ TemplateArgs, loc, parm->getDeclName());
+ } else {
+ type = SemaRef.SubstType(parm->getType(), TemplateArgs,
+ loc, parm->getDeclName());
+ }
+ assert(!type.isNull() && "type substitution failed for param type");
+ assert(!type->isDependentType() && "param type still dependent");
+ result = SemaRef.BuildExpressionFromDeclTemplateArgument(arg, type, loc);
+
+ if (!result.isInvalid()) type = result.get()->getType();
+ } else {
+ result = SemaRef.BuildExpressionFromIntegralTemplateArgument(arg, loc);
+
+ // Note that this type can be different from the type of 'result',
+ // e.g. if it's an enum type.
+ type = arg.getIntegralType();
}
+ if (result.isInvalid()) return ExprError();
- return SemaRef.BuildExpressionFromIntegralTemplateArgument(Arg,
- E->getSourceRange().getBegin());
+ Expr *resultExpr = result.take();
+ return SemaRef.Owned(new (SemaRef.Context)
+ SubstNonTypeTemplateParmExpr(type,
+ resultExpr->getValueKind(),
+ loc, parm, resultExpr));
}
ExprResult
@@ -1120,36 +1157,9 @@ TemplateInstantiator::TransformSubstNonTypeTemplateParmPackExpr(
assert(Index < ArgPack.pack_size() && "Substitution index out-of-range");
const TemplateArgument &Arg = ArgPack.pack_begin()[Index];
- if (Arg.getKind() == TemplateArgument::Expression)
- return SemaRef.Owned(Arg.getAsExpr());
-
- if (Arg.getKind() == TemplateArgument::Declaration) {
- ValueDecl *VD = cast<ValueDecl>(Arg.getAsDecl());
-
- // Find the instantiation of the template argument. This is
- // required for nested templates.
- VD = cast_or_null<ValueDecl>(
- getSema().FindInstantiatedDecl(E->getParameterPackLocation(),
- VD, TemplateArgs));
- if (!VD)
- return ExprError();
-
- QualType T;
- NonTypeTemplateParmDecl *NTTP = E->getParameterPack();
- if (NTTP->isExpandedParameterPack())
- T = NTTP->getExpansionType(getSema().ArgumentPackSubstitutionIndex);
- else if (const PackExpansionType *Expansion
- = dyn_cast<PackExpansionType>(NTTP->getType()))
- T = SemaRef.SubstType(Expansion->getPattern(), TemplateArgs,
- E->getParameterPackLocation(), NTTP->getDeclName());
- else
- T = E->getType();
- return SemaRef.BuildExpressionFromDeclTemplateArgument(Arg, T,
- E->getParameterPackLocation());
- }
-
- return SemaRef.BuildExpressionFromIntegralTemplateArgument(Arg,
- E->getParameterPackLocation());
+ return transformNonTypeTemplateParmRef(E->getParameterPack(),
+ E->getParameterPackLocation(),
+ Arg);
}
ExprResult
@@ -1327,7 +1337,7 @@ TypeSourceInfo *Sema::SubstType(TypeSourceInfo *T,
"Cannot perform an instantiation without some context on the "
"instantiation stack");
- if (!T->getType()->isDependentType() &&
+ if (!T->getType()->isInstantiationDependentType() &&
!T->getType()->isVariablyModifiedType())
return T;
@@ -1346,7 +1356,7 @@ TypeSourceInfo *Sema::SubstType(TypeLoc TL,
if (TL.getType().isNull())
return 0;
- if (!TL.getType()->isDependentType() &&
+ if (!TL.getType()->isInstantiationDependentType() &&
!TL.getType()->isVariablyModifiedType()) {
// FIXME: Make a copy of the TypeLoc data here, so that we can
// return a new TypeSourceInfo. Inefficient!
@@ -1375,7 +1385,7 @@ QualType Sema::SubstType(QualType T,
// If T is not a dependent type or a variably-modified type, there
// is nothing to do.
- if (!T->isDependentType() && !T->isVariablyModifiedType())
+ if (!T->isInstantiationDependentType() && !T->isVariablyModifiedType())
return T;
TemplateInstantiator Instantiator(*this, TemplateArgs, Loc, Entity);
@@ -1383,7 +1393,8 @@ QualType Sema::SubstType(QualType T,
}
static bool NeedsInstantiationAsFunctionType(TypeSourceInfo *T) {
- if (T->getType()->isDependentType() || T->getType()->isVariablyModifiedType())
+ if (T->getType()->isInstantiationDependentType() ||
+ T->getType()->isVariablyModifiedType())
return true;
TypeLoc TL = T->getTypeLoc().IgnoreParens();
@@ -1397,7 +1408,7 @@ static bool NeedsInstantiationAsFunctionType(TypeSourceInfo *T) {
// The parameter's type as written might be dependent even if the
// decayed type was not dependent.
if (TypeSourceInfo *TSInfo = P->getTypeSourceInfo())
- if (TSInfo->getType()->isDependentType())
+ if (TSInfo->getType()->isInstantiationDependentType())
return true;
// TODO: currently we always rebuild expressions. When we
@@ -1798,9 +1809,11 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
ExprResult NewInit = SubstExpr(OldInit, TemplateArgs);
// If the initialization is no longer dependent, check it now.
- if ((OldField->getType()->isDependentType() || OldInit->isTypeDependent())
- && !NewField->getType()->isDependentType()
- && !NewInit.get()->isTypeDependent()) {
+ if ((OldField->getType()->isDependentType() || OldInit->isTypeDependent() ||
+ OldInit->isValueDependent()) &&
+ !NewField->getType()->isDependentType() &&
+ !NewInit.get()->isTypeDependent() &&
+ !NewInit.get()->isValueDependent()) {
// FIXME: handle list-initialization
SourceLocation EqualLoc = NewField->getLocation();
NewInit = PerformCopyInitialization(
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index e78aa2991e74..29385e50b8c1 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -59,7 +59,7 @@ bool TemplateDeclInstantiator::SubstQualifier(const TagDecl *OldDecl,
// FIXME: Is this still too simple?
void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
- Decl *Tmpl, Decl *New) {
+ const Decl *Tmpl, Decl *New) {
for (AttrVec::const_iterator i = Tmpl->attr_begin(), e = Tmpl->attr_end();
i != e; ++i) {
const Attr *TmplAttr = *i;
@@ -132,7 +132,7 @@ Decl *TemplateDeclInstantiator::InstantiateTypedefNameDecl(TypedefNameDecl *D,
bool IsTypeAlias) {
bool Invalid = false;
TypeSourceInfo *DI = D->getTypeSourceInfo();
- if (DI->getType()->isDependentType() ||
+ if (DI->getType()->isInstantiationDependentType() ||
DI->getType()->isVariablyModifiedType()) {
DI = SemaRef.SubstType(DI, TemplateArgs,
D->getLocation(), D->getDeclName());
@@ -415,8 +415,10 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
!Var->isCXXForRangeDecl())
SemaRef.ActOnUninitializedDecl(Var, false);
- // Diagnose unused local variables.
- if (!Var->isInvalidDecl() && Owner->isFunctionOrMethod() && !Var->isUsed())
+ // Diagnose unused local variables with dependent types, where the diagnostic
+ // will have been deferred.
+ if (!Var->isInvalidDecl() && Owner->isFunctionOrMethod() && !Var->isUsed() &&
+ D->getType()->isDependentType())
SemaRef.DiagnoseUnusedDecl(Var);
return Var;
@@ -433,7 +435,7 @@ Decl *TemplateDeclInstantiator::VisitAccessSpecDecl(AccessSpecDecl *D) {
Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
bool Invalid = false;
TypeSourceInfo *DI = D->getTypeSourceInfo();
- if (DI->getType()->isDependentType() ||
+ if (DI->getType()->isInstantiationDependentType() ||
DI->getType()->isVariablyModifiedType()) {
DI = SemaRef.SubstType(DI, TemplateArgs,
D->getLocation(), D->getDeclName());
@@ -1088,9 +1090,26 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
Function->setLexicalDeclContext(LexicalDC);
// Attach the parameters
- for (unsigned P = 0; P < Params.size(); ++P)
- if (Params[P])
- Params[P]->setOwningFunction(Function);
+ if (isa<FunctionProtoType>(Function->getType().IgnoreParens())) {
+ // Adopt the already-instantiated parameters into our own context.
+ for (unsigned P = 0; P < Params.size(); ++P)
+ if (Params[P])
+ Params[P]->setOwningFunction(Function);
+ } else {
+ // Since we were instantiated via a typedef of a function type, create
+ // new parameters.
+ const FunctionProtoType *Proto
+ = Function->getType()->getAs<FunctionProtoType>();
+ assert(Proto && "No function prototype in template instantiation?");
+ for (FunctionProtoType::arg_type_iterator AI = Proto->arg_type_begin(),
+ AE = Proto->arg_type_end(); AI != AE; ++AI) {
+ ParmVarDecl *Param
+ = SemaRef.BuildParmVarDeclForTypedef(Function, Function->getLocation(),
+ *AI);
+ Param->setScopeInfo(0, Params.size());
+ Params.push_back(Param);
+ }
+ }
Function->setParams(Params.data(), Params.size());
SourceLocation InstantiateAtPOI;
@@ -2264,7 +2283,12 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
EPI));
}
- SemaRef.InstantiateAttrs(TemplateArgs, Tmpl, New);
+ const FunctionDecl* Definition = Tmpl;
+
+ // Get the definition. Leaves the variable unchanged if undefined.
+ Tmpl->isDefined(Definition);
+
+ SemaRef.InstantiateAttrs(TemplateArgs, Definition, New);
return false;
}
diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp
index 86d3bc170909..daa1523363c0 100644
--- a/lib/Sema/SemaTemplateVariadic.cpp
+++ b/lib/Sema/SemaTemplateVariadic.cpp
@@ -716,17 +716,19 @@ ExprResult Sema::ActOnSizeofParameterPackExpr(Scope *S,
case LookupResult::NotFound:
case LookupResult::NotFoundInCurrentInstantiation:
- if (DeclarationName CorrectedName = CorrectTypo(R, S, 0, 0, false,
- CTC_NoKeywords)) {
- if (NamedDecl *CorrectedResult = R.getAsSingle<NamedDecl>())
+ if (TypoCorrection Corrected = CorrectTypo(R.getLookupNameInfo(),
+ R.getLookupKind(), S, 0, 0,
+ false, CTC_NoKeywords)) {
+ if (NamedDecl *CorrectedResult = Corrected.getCorrectionDecl())
if (CorrectedResult->isParameterPack()) {
+ std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOptions()));
ParameterPack = CorrectedResult;
Diag(NameLoc, diag::err_sizeof_pack_no_pack_name_suggest)
- << &Name << CorrectedName
- << FixItHint::CreateReplacement(NameLoc,
- CorrectedName.getAsString());
+ << &Name << CorrectedQuotedStr
+ << FixItHint::CreateReplacement(
+ NameLoc, Corrected.getAsString(getLangOptions()));
Diag(ParameterPack->getLocation(), diag::note_parameter_pack_here)
- << CorrectedName;
+ << CorrectedQuotedStr;
}
}
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 5fd8afa6acf4..f3e73ec5a723 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -26,36 +26,11 @@
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/DeclSpec.h"
+#include "clang/Sema/DelayedDiagnostic.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
-/// \brief Perform adjustment on the parameter type of a function.
-///
-/// This routine adjusts the given parameter type @p T to the actual
-/// parameter type used by semantic analysis (C99 6.7.5.3p[7,8],
-/// C++ [dcl.fct]p3). The adjusted parameter type is returned.
-QualType Sema::adjustParameterType(QualType T) {
- // C99 6.7.5.3p7:
- // 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 Context.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 Context.getPointerType(T);
-
- return T;
-}
-
-
-
/// isOmittedBlockReturnType - Return true if this declarator is missing a
/// return type because this is a omitted return type on a block literal.
static bool isOmittedBlockReturnType(const Declarator &D) {
@@ -86,6 +61,11 @@ static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr,
useInstantiationLoc = true;
break;
+ case AttributeList::AT_objc_ownership:
+ diagID = diag::warn_objc_object_attribute_wrong_type;
+ useInstantiationLoc = true;
+ break;
+
default:
// Assume everything else was a function attribute.
diagID = diag::warn_function_attribute_wrong_type;
@@ -110,7 +90,8 @@ static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr,
// objc_gc applies to Objective-C pointers or, otherwise, to the
// smallest available pointer type (i.e. 'void*' in 'void**').
#define OBJC_POINTER_TYPE_ATTRS_CASELIST \
- case AttributeList::AT_objc_gc
+ case AttributeList::AT_objc_gc: \
+ case AttributeList::AT_objc_ownership
// Function type attributes.
#define FUNCTION_TYPE_ATTRS_CASELIST \
@@ -295,11 +276,15 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state,
static bool handleObjCGCTypeAttr(TypeProcessingState &state,
AttributeList &attr, QualType &type);
+static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
+ AttributeList &attr, QualType &type);
+
static bool handleObjCPointerTypeAttr(TypeProcessingState &state,
AttributeList &attr, QualType &type) {
- // Right now, we have exactly one of these attributes: objc_gc.
- assert(attr.getKind() == AttributeList::AT_objc_gc);
- return handleObjCGCTypeAttr(state, attr, type);
+ if (attr.getKind() == AttributeList::AT_objc_gc)
+ return handleObjCGCTypeAttr(state, attr, type);
+ assert(attr.getKind() == AttributeList::AT_objc_ownership);
+ return handleObjCOwnershipTypeAttr(state, attr, type);
}
/// Given that an objc_gc attribute was written somewhere on a
@@ -447,7 +432,12 @@ distributeFunctionTypeAttrToInnermost(TypeProcessingState &state,
return true;
}
- return handleFunctionTypeAttr(state, attr, declSpecType);
+ if (handleFunctionTypeAttr(state, attr, declSpecType)) {
+ spliceAttrOutOfList(attr, attrList);
+ return true;
+ }
+
+ return false;
}
/// A function type attribute was written in the decl spec. Try to
@@ -512,6 +502,11 @@ static void distributeTypeAttrsFromDeclarator(TypeProcessingState &state,
distributeObjCPointerTypeAttrFromDeclarator(state, *attr, declSpecType);
break;
+ case AttributeList::AT_ns_returns_retained:
+ if (!state.getSema().getLangOptions().ObjCAutoRefCount)
+ break;
+ // fallthrough
+
FUNCTION_TYPE_ATTRS_CASELIST:
distributeFunctionTypeAttrFromDeclarator(state, *attr, declSpecType);
break;
@@ -560,6 +555,7 @@ static void maybeSynthesizeBlockSignature(TypeProcessingState &state,
/*args*/ 0, 0,
/*type quals*/ 0,
/*ref-qualifier*/true, SourceLocation(),
+ /*mutable qualifier*/SourceLocation(),
/*EH*/ EST_None, SourceLocation(), 0, 0, 0, 0,
/*parens*/ loc, loc,
declarator));
@@ -575,10 +571,11 @@ static void maybeSynthesizeBlockSignature(TypeProcessingState &state,
/// \param D the declarator containing the declaration specifier.
/// \returns The type described by the declaration specifiers. This function
/// never returns null.
-static QualType ConvertDeclSpecToType(Sema &S, TypeProcessingState &state) {
+static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
// FIXME: Should move the logic from DeclSpec::Finish to here for validity
// checking.
+ Sema &S = state.getSema();
Declarator &declarator = state.getDeclarator();
const DeclSpec &DS = declarator.getDeclSpec();
SourceLocation DeclLoc = declarator.getIdentifierLoc();
@@ -1017,6 +1014,51 @@ QualType Sema::BuildParenType(QualType T) {
return Context.getParenType(T);
}
+/// Given that we're building a pointer or reference to the given
+static QualType inferARCLifetimeForPointee(Sema &S, QualType type,
+ SourceLocation loc,
+ bool isReference) {
+ // Bail out if retention is unrequired or already specified.
+ if (!type->isObjCLifetimeType() ||
+ type.getObjCLifetime() != Qualifiers::OCL_None)
+ return type;
+
+ Qualifiers::ObjCLifetime implicitLifetime = Qualifiers::OCL_None;
+
+ // If the object type is const-qualified, we can safely use
+ // __unsafe_unretained. This is safe (because there are no read
+ // barriers), and it'll be safe to coerce anything but __weak* to
+ // the resulting type.
+ if (type.isConstQualified()) {
+ implicitLifetime = Qualifiers::OCL_ExplicitNone;
+
+ // Otherwise, check whether the static type does not require
+ // retaining. This currently only triggers for Class (possibly
+ // protocol-qualifed, and arrays thereof).
+ } else if (type->isObjCARCImplicitlyUnretainedType()) {
+ implicitLifetime = Qualifiers::OCL_ExplicitNone;
+
+ // If that failed, give an error and recover using __autoreleasing.
+ } else {
+ // These types can show up in private ivars in system headers, so
+ // we need this to not be an error in those cases. Instead we
+ // want to delay.
+ if (S.DelayedDiagnostics.shouldDelayDiagnostics()) {
+ S.DelayedDiagnostics.add(
+ sema::DelayedDiagnostic::makeForbiddenType(loc,
+ diag::err_arc_indirect_no_ownership, type, isReference));
+ } else {
+ S.Diag(loc, diag::err_arc_indirect_no_ownership) << type << isReference;
+ }
+ implicitLifetime = Qualifiers::OCL_Autoreleasing;
+ }
+ assert(implicitLifetime && "didn't infer any lifetime!");
+
+ Qualifiers qs;
+ qs.addObjCLifetime(implicitLifetime);
+ return S.Context.getQualifiedType(type, qs);
+}
+
/// \brief Build a pointer type.
///
/// \param T The type to which we'll be building a pointer.
@@ -1041,6 +1083,10 @@ QualType Sema::BuildPointerType(QualType T,
assert(!T->isObjCObjectType() && "Should build ObjCObjectPointerType");
+ // In ARC, it is forbidden to build pointers to unqualified pointers.
+ if (getLangOptions().ObjCAutoRefCount)
+ T = inferARCLifetimeForPointee(*this, T, Loc, /*reference*/ false);
+
// Build the pointer type.
return Context.getPointerType(T);
}
@@ -1094,12 +1140,38 @@ QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue,
return QualType();
}
+ // In ARC, it is forbidden to build references to unqualified pointers.
+ if (getLangOptions().ObjCAutoRefCount)
+ T = inferARCLifetimeForPointee(*this, T, Loc, /*reference*/ true);
+
// Handle restrict on references.
if (LValueRef)
return Context.getLValueReferenceType(T, SpelledAsLValue);
return Context.getRValueReferenceType(T);
}
+/// Check whether the specified array size makes the array type a VLA. If so,
+/// return true, if not, return the size of the array in SizeVal.
+static bool isArraySizeVLA(Expr *ArraySize, llvm::APSInt &SizeVal, Sema &S) {
+ // If the size is an ICE, it certainly isn't a VLA.
+ if (ArraySize->isIntegerConstantExpr(SizeVal, S.Context))
+ return false;
+
+ // If we're in a GNU mode (like gnu99, but not c99) accept any evaluatable
+ // value as an extension.
+ Expr::EvalResult Result;
+ if (S.LangOpts.GNUMode && ArraySize->Evaluate(Result, S.Context)) {
+ if (!Result.hasSideEffects() && Result.Val.isInt()) {
+ SizeVal = Result.Val.getInt();
+ S.Diag(ArraySize->getLocStart(), diag::ext_vla_folded_to_constant);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
/// \brief Build an array type.
///
/// \param T The type of each element in the array.
@@ -1200,11 +1272,13 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
T = Context.getIncompleteArrayType(T, ASM, Quals);
} else if (ArraySize->isTypeDependent() || ArraySize->isValueDependent()) {
T = Context.getDependentSizedArrayType(T, ArraySize, ASM, Quals, Brackets);
- } else if (!ArraySize->isIntegerConstantExpr(ConstVal, Context) ||
- (!T->isDependentType() && !T->isIncompleteType() &&
- !T->isConstantSizeType())) {
- // Per C99, a variable array is an array with either a non-constant
- // size or an element type that has a non-constant-size
+ } else if (!T->isDependentType() && !T->isIncompleteType() &&
+ !T->isConstantSizeType()) {
+ // C99: an array with an element type that has a non-constant-size is a VLA.
+ T = Context.getVariableArrayType(T, ArraySize, ASM, Quals, Brackets);
+ } else if (isArraySizeVLA(ArraySize, ConstVal, *this)) {
+ // C99: an array with a non-ICE size is a VLA. We accept any expression
+ // that we can fold to a non-zero positive value as an extension.
T = Context.getVariableArrayType(T, ArraySize, ASM, Quals, Brackets);
} else {
// C99 6.7.5.2p1: If the expression is a constant expression, it shall
@@ -1242,10 +1316,12 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
if (!getLangOptions().C99) {
if (T->isVariableArrayType()) {
// Prohibit the use of non-POD types in VLAs.
+ QualType BaseT = Context.getBaseElementType(T);
if (!T->isDependentType() &&
- !Context.getBaseElementType(T)->isPODType()) {
+ !BaseT.isPODType(Context) &&
+ !BaseT->isObjCLifetimeType()) {
Diag(Loc, diag::err_vla_non_pod)
- << Context.getBaseElementType(T);
+ << BaseT;
return QualType();
}
// Prohibit the use of VLAs during template argument deduction.
@@ -1296,8 +1372,7 @@ QualType Sema::BuildExtVectorType(QualType T, Expr *ArraySize,
return QualType();
}
- if (!T->isDependentType())
- return Context.getExtVectorType(T, vectorSize);
+ return Context.getExtVectorType(T, vectorSize);
}
return Context.getDependentSizedExtVectorType(T, ArraySize, AttrLoc);
@@ -1347,7 +1422,7 @@ QualType Sema::BuildFunctionType(QualType T,
bool Invalid = false;
for (unsigned Idx = 0; Idx < NumParamTypes; ++Idx) {
- QualType ParamType = adjustParameterType(ParamTypes[Idx]);
+ QualType ParamType = Context.getAdjustedParameterType(ParamTypes[Idx]);
if (ParamType->isVoidType()) {
Diag(Loc, diag::err_param_with_void_type);
Invalid = true;
@@ -1467,6 +1542,109 @@ QualType Sema::GetTypeFromParser(ParsedType Ty, TypeSourceInfo **TInfo) {
return QT;
}
+static void transferARCOwnershipToDeclaratorChunk(TypeProcessingState &state,
+ Qualifiers::ObjCLifetime ownership,
+ unsigned chunkIndex);
+
+/// Given that this is the declaration of a parameter under ARC,
+/// attempt to infer attributes and such for pointer-to-whatever
+/// types.
+static void inferARCWriteback(TypeProcessingState &state,
+ QualType &declSpecType) {
+ Sema &S = state.getSema();
+ Declarator &declarator = state.getDeclarator();
+
+ // TODO: should we care about decl qualifiers?
+
+ // Check whether the declarator has the expected form. We walk
+ // from the inside out in order to make the block logic work.
+ unsigned outermostPointerIndex = 0;
+ bool isBlockPointer = false;
+ unsigned numPointers = 0;
+ for (unsigned i = 0, e = declarator.getNumTypeObjects(); i != e; ++i) {
+ unsigned chunkIndex = i;
+ DeclaratorChunk &chunk = declarator.getTypeObject(chunkIndex);
+ switch (chunk.Kind) {
+ case DeclaratorChunk::Paren:
+ // Ignore parens.
+ break;
+
+ case DeclaratorChunk::Reference:
+ case DeclaratorChunk::Pointer:
+ // Count the number of pointers. Treat references
+ // interchangeably as pointers; if they're mis-ordered, normal
+ // type building will discover that.
+ outermostPointerIndex = chunkIndex;
+ numPointers++;
+ break;
+
+ case DeclaratorChunk::BlockPointer:
+ // If we have a pointer to block pointer, that's an acceptable
+ // indirect reference; anything else is not an application of
+ // the rules.
+ if (numPointers != 1) return;
+ numPointers++;
+ outermostPointerIndex = chunkIndex;
+ isBlockPointer = true;
+
+ // We don't care about pointer structure in return values here.
+ goto done;
+
+ case DeclaratorChunk::Array: // suppress if written (id[])?
+ case DeclaratorChunk::Function:
+ case DeclaratorChunk::MemberPointer:
+ return;
+ }
+ }
+ done:
+
+ // If we have *one* pointer, then we want to throw the qualifier on
+ // the declaration-specifiers, which means that it needs to be a
+ // retainable object type.
+ if (numPointers == 1) {
+ // If it's not a retainable object type, the rule doesn't apply.
+ if (!declSpecType->isObjCRetainableType()) return;
+
+ // If it already has lifetime, don't do anything.
+ if (declSpecType.getObjCLifetime()) return;
+
+ // Otherwise, modify the type in-place.
+ Qualifiers qs;
+
+ if (declSpecType->isObjCARCImplicitlyUnretainedType())
+ qs.addObjCLifetime(Qualifiers::OCL_ExplicitNone);
+ else
+ qs.addObjCLifetime(Qualifiers::OCL_Autoreleasing);
+ declSpecType = S.Context.getQualifiedType(declSpecType, qs);
+
+ // If we have *two* pointers, then we want to throw the qualifier on
+ // the outermost pointer.
+ } else if (numPointers == 2) {
+ // If we don't have a block pointer, we need to check whether the
+ // declaration-specifiers gave us something that will turn into a
+ // retainable object pointer after we slap the first pointer on it.
+ if (!isBlockPointer && !declSpecType->isObjCObjectType())
+ return;
+
+ // Look for an explicit lifetime attribute there.
+ DeclaratorChunk &chunk = declarator.getTypeObject(outermostPointerIndex);
+ if (chunk.Kind != DeclaratorChunk::Pointer &&
+ chunk.Kind != DeclaratorChunk::BlockPointer)
+ return;
+ for (const AttributeList *attr = chunk.getAttrs(); attr;
+ attr = attr->getNext())
+ if (attr->getKind() == AttributeList::AT_objc_ownership)
+ return;
+
+ transferARCOwnershipToDeclaratorChunk(state, Qualifiers::OCL_Autoreleasing,
+ outermostPointerIndex);
+
+ // Any other number of pointers/references does not trigger the rule.
+ } else return;
+
+ // TODO: mark whether we did this inference?
+}
+
static void DiagnoseIgnoredQualifiers(unsigned Quals,
SourceLocation ConstQualLoc,
SourceLocation VolatileQualLoc,
@@ -1513,47 +1691,28 @@ static void DiagnoseIgnoredQualifiers(unsigned Quals,
<< QualStr << NumQuals << ConstFixIt << VolatileFixIt << RestrictFixIt;
}
-/// GetTypeForDeclarator - Convert the type for the specified
-/// declarator to Type instances.
-///
-/// If OwnedDecl is non-NULL, and this declarator's decl-specifier-seq
-/// owns the declaration of a type (e.g., the definition of a struct
-/// type), then *OwnedDecl will receive the owned declaration.
-///
-/// The result of this call will never be null, but the associated
-/// type may be a null type if there's an unrecoverable error.
-TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
- TagDecl **OwnedDecl,
- bool AutoAllowedInTypeName) {
- // Determine the type of the declarator. Not all forms of declarator
- // have a type.
+static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
+ TypeSourceInfo *&ReturnTypeInfo) {
+ Sema &SemaRef = state.getSema();
+ Declarator &D = state.getDeclarator();
QualType T;
- TypeSourceInfo *ReturnTypeInfo = 0;
-
- TypeProcessingState state(*this, D);
+ ReturnTypeInfo = 0;
- // In C++0x, deallocation functions (normal and array operator delete)
- // are implicitly noexcept.
- bool ImplicitlyNoexcept = false;
+ // The TagDecl owned by the DeclSpec.
+ TagDecl *OwnedTagDecl = 0;
switch (D.getName().getKind()) {
+ case UnqualifiedId::IK_ImplicitSelfParam:
case UnqualifiedId::IK_OperatorFunctionId:
- if (getLangOptions().CPlusPlus0x) {
- OverloadedOperatorKind OO = D.getName().OperatorFunctionId.Operator;
- if (OO == OO_Delete || OO == OO_Array_Delete)
- ImplicitlyNoexcept = true;
- }
- // Intentional fall-through.
case UnqualifiedId::IK_Identifier:
case UnqualifiedId::IK_LiteralOperatorId:
case UnqualifiedId::IK_TemplateId:
- T = ConvertDeclSpecToType(*this, state);
+ T = ConvertDeclSpecToType(state);
if (!D.isInvalidType() && D.getDeclSpec().isTypeSpecOwned()) {
- TagDecl* Owned = cast<TagDecl>(D.getDeclSpec().getRepAsDecl());
+ OwnedTagDecl = cast<TagDecl>(D.getDeclSpec().getRepAsDecl());
// Owned declaration is embedded in declarator.
- Owned->setEmbeddedInDeclarator(true);
- if (OwnedDecl) *OwnedDecl = Owned;
+ OwnedTagDecl->setEmbeddedInDeclarator(true);
}
break;
@@ -1562,14 +1721,14 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
case UnqualifiedId::IK_DestructorName:
// Constructors and destructors don't have return types. Use
// "void" instead.
- T = Context.VoidTy;
+ T = SemaRef.Context.VoidTy;
break;
case UnqualifiedId::IK_ConversionFunctionId:
// The result type of a conversion function is the type that it
// converts to.
- T = GetTypeFromParser(D.getName().ConversionFunctionId,
- &ReturnTypeInfo);
+ T = SemaRef.GetTypeFromParser(D.getName().ConversionFunctionId,
+ &ReturnTypeInfo);
break;
}
@@ -1581,7 +1740,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// type (this is checked later) and we can skip this. In other languages
// using auto, we need to check regardless.
if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto &&
- (!getLangOptions().CPlusPlus0x || !D.isFunctionDeclarator())) {
+ (!SemaRef.getLangOptions().CPlusPlus0x || !D.isFunctionDeclarator())) {
int Error = -1;
switch (D.getContext()) {
@@ -1595,7 +1754,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
case Declarator::MemberContext:
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static)
break;
- switch (cast<TagDecl>(CurContext)->getTagKind()) {
+ switch (cast<TagDecl>(SemaRef.CurContext)->getTagKind()) {
case TTK_Enum: assert(0 && "unhandled tag kind"); break;
case TTK_Struct: Error = 1; /* Struct member */ break;
case TTK_Union: Error = 2; /* Union member */ break;
@@ -1603,6 +1762,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
}
break;
case Declarator::CXXCatchContext:
+ case Declarator::ObjCCatchContext:
Error = 4; // Exception declaration
break;
case Declarator::TemplateParamContext:
@@ -1619,13 +1779,13 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
Error = 9; // Type alias
break;
case Declarator::TypeNameContext:
- if (!AutoAllowedInTypeName)
- Error = 11; // Generic
+ Error = 11; // Generic
break;
case Declarator::FileContext:
case Declarator::BlockContext:
case Declarator::ForContext:
case Declarator::ConditionContext:
+ case Declarator::CXXNewContext:
break;
}
@@ -1640,7 +1800,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// contains a trailing return type. That is only legal at the outermost
// level. Check all declarator chunks (outermost first) anyway, to give
// better diagnostics.
- if (getLangOptions().CPlusPlus0x && Error != -1) {
+ if (SemaRef.getLangOptions().CPlusPlus0x && Error != -1) {
for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
unsigned chunkIndex = e - i - 1;
state.setCurrentChunkIndex(chunkIndex);
@@ -1656,15 +1816,86 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
}
if (Error != -1) {
- Diag(D.getDeclSpec().getTypeSpecTypeLoc(), diag::err_auto_not_allowed)
+ SemaRef.Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
+ diag::err_auto_not_allowed)
<< Error;
- T = Context.IntTy;
+ T = SemaRef.Context.IntTy;
D.setInvalidType(true);
}
}
-
- if (T.isNull())
- return Context.getNullTypeSourceInfo();
+
+ if (SemaRef.getLangOptions().CPlusPlus &&
+ OwnedTagDecl && OwnedTagDecl->isDefinition()) {
+ // Check the contexts where C++ forbids the declaration of a new class
+ // or enumeration in a type-specifier-seq.
+ switch (D.getContext()) {
+ case Declarator::FileContext:
+ case Declarator::MemberContext:
+ case Declarator::BlockContext:
+ case Declarator::ForContext:
+ case Declarator::BlockLiteralContext:
+ // C++0x [dcl.type]p3:
+ // A type-specifier-seq shall not define a class or enumeration unless
+ // it appears in the type-id of an alias-declaration (7.1.3) that is not
+ // the declaration of a template-declaration.
+ case Declarator::AliasDeclContext:
+ break;
+ case Declarator::AliasTemplateContext:
+ SemaRef.Diag(OwnedTagDecl->getLocation(),
+ diag::err_type_defined_in_alias_template)
+ << SemaRef.Context.getTypeDeclType(OwnedTagDecl);
+ break;
+ case Declarator::TypeNameContext:
+ case Declarator::TemplateParamContext:
+ case Declarator::CXXNewContext:
+ case Declarator::CXXCatchContext:
+ case Declarator::ObjCCatchContext:
+ case Declarator::TemplateTypeArgContext:
+ SemaRef.Diag(OwnedTagDecl->getLocation(),
+ diag::err_type_defined_in_type_specifier)
+ << SemaRef.Context.getTypeDeclType(OwnedTagDecl);
+ break;
+ case Declarator::PrototypeContext:
+ case Declarator::ObjCPrototypeContext:
+ case Declarator::KNRTypeListContext:
+ // C++ [dcl.fct]p6:
+ // Types shall not be defined in return or parameter types.
+ SemaRef.Diag(OwnedTagDecl->getLocation(),
+ diag::err_type_defined_in_param_type)
+ << SemaRef.Context.getTypeDeclType(OwnedTagDecl);
+ break;
+ case Declarator::ConditionContext:
+ // C++ 6.4p2:
+ // The type-specifier-seq shall not contain typedef and shall not declare
+ // a new class or enumeration.
+ SemaRef.Diag(OwnedTagDecl->getLocation(),
+ diag::err_type_defined_in_condition);
+ break;
+ }
+ }
+
+ return T;
+}
+
+static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
+ QualType declSpecType,
+ TypeSourceInfo *TInfo) {
+
+ QualType T = declSpecType;
+ Declarator &D = state.getDeclarator();
+ Sema &S = state.getSema();
+ ASTContext &Context = S.Context;
+ const LangOptions &LangOpts = S.getLangOptions();
+
+ bool ImplicitlyNoexcept = false;
+ if (D.getName().getKind() == UnqualifiedId::IK_OperatorFunctionId &&
+ LangOpts.CPlusPlus0x) {
+ OverloadedOperatorKind OO = D.getName().OperatorFunctionId.Operator;
+ /// In C++0x, deallocation functions (normal and array operator delete)
+ /// are implicitly noexcept.
+ if (OO == OO_Delete || OO == OO_Array_Delete)
+ ImplicitlyNoexcept = true;
+ }
// The name we're declaring, if any.
DeclarationName Name;
@@ -1687,56 +1918,56 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
switch (DeclType.Kind) {
default: assert(0 && "Unknown decltype!");
case DeclaratorChunk::Paren:
- T = BuildParenType(T);
+ T = S.BuildParenType(T);
break;
case DeclaratorChunk::BlockPointer:
// If blocks are disabled, emit an error.
if (!LangOpts.Blocks)
- Diag(DeclType.Loc, diag::err_blocks_disable);
+ S.Diag(DeclType.Loc, diag::err_blocks_disable);
- T = BuildBlockPointerType(T, D.getIdentifierLoc(), Name);
+ T = S.BuildBlockPointerType(T, D.getIdentifierLoc(), Name);
if (DeclType.Cls.TypeQuals)
- T = BuildQualifiedType(T, DeclType.Loc, DeclType.Cls.TypeQuals);
+ T = S.BuildQualifiedType(T, DeclType.Loc, DeclType.Cls.TypeQuals);
break;
case DeclaratorChunk::Pointer:
// Verify that we're not building a pointer to pointer to function with
// exception specification.
- if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) {
- Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec);
+ if (LangOpts.CPlusPlus && S.CheckDistantExceptionSpec(T)) {
+ S.Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec);
D.setInvalidType(true);
// Build the type anyway.
}
- if (getLangOptions().ObjC1 && T->getAs<ObjCObjectType>()) {
+ if (LangOpts.ObjC1 && T->getAs<ObjCObjectType>()) {
T = Context.getObjCObjectPointerType(T);
if (DeclType.Ptr.TypeQuals)
- T = BuildQualifiedType(T, DeclType.Loc, DeclType.Ptr.TypeQuals);
+ T = S.BuildQualifiedType(T, DeclType.Loc, DeclType.Ptr.TypeQuals);
break;
}
- T = BuildPointerType(T, DeclType.Loc, Name);
+ T = S.BuildPointerType(T, DeclType.Loc, Name);
if (DeclType.Ptr.TypeQuals)
- T = BuildQualifiedType(T, DeclType.Loc, DeclType.Ptr.TypeQuals);
+ T = S.BuildQualifiedType(T, DeclType.Loc, DeclType.Ptr.TypeQuals);
break;
case DeclaratorChunk::Reference: {
// Verify that we're not building a reference to pointer to function with
// exception specification.
- if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) {
- Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec);
+ if (LangOpts.CPlusPlus && S.CheckDistantExceptionSpec(T)) {
+ S.Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec);
D.setInvalidType(true);
// Build the type anyway.
}
- T = BuildReferenceType(T, DeclType.Ref.LValueRef, DeclType.Loc, Name);
+ T = S.BuildReferenceType(T, DeclType.Ref.LValueRef, DeclType.Loc, Name);
Qualifiers Quals;
if (DeclType.Ref.HasRestrict)
- T = BuildQualifiedType(T, DeclType.Loc, Qualifiers::Restrict);
+ T = S.BuildQualifiedType(T, DeclType.Loc, Qualifiers::Restrict);
break;
}
case DeclaratorChunk::Array: {
// Verify that we're not building an array of pointers to function with
// exception specification.
- if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) {
- Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec);
+ if (LangOpts.CPlusPlus && S.CheckDistantExceptionSpec(T)) {
+ S.Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec);
D.setInvalidType(true);
// Build the type anyway.
}
@@ -1753,13 +1984,13 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// FIXME: This check isn't quite right: it allows star in prototypes
// for function definitions, and disallows some edge cases detailed
// in http://gcc.gnu.org/ml/gcc-patches/2009-02/msg00133.html
- Diag(DeclType.Loc, diag::err_array_star_outside_prototype);
+ S.Diag(DeclType.Loc, diag::err_array_star_outside_prototype);
ASM = ArrayType::Normal;
D.setInvalidType(true);
}
- T = BuildArrayType(T, ASM, ArraySize,
- Qualifiers::fromCVRMask(ATI.TypeQuals),
- SourceRange(DeclType.Loc, DeclType.EndLoc), Name);
+ T = S.BuildArrayType(T, ASM, ArraySize,
+ Qualifiers::fromCVRMask(ATI.TypeQuals),
+ SourceRange(DeclType.Loc, DeclType.EndLoc), Name);
break;
}
case DeclaratorChunk::Function: {
@@ -1775,27 +2006,27 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// and not, for instance, a pointer to a function.
if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto &&
!FTI.TrailingReturnType && chunkIndex == 0) {
- Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
+ S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
diag::err_auto_missing_trailing_return);
T = Context.IntTy;
D.setInvalidType(true);
} else if (FTI.TrailingReturnType) {
// T must be exactly 'auto' at this point. See CWG issue 681.
if (isa<ParenType>(T)) {
- Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
+ S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
diag::err_trailing_return_in_parens)
<< T << D.getDeclSpec().getSourceRange();
D.setInvalidType(true);
} else if (T.hasQualifiers() || !isa<AutoType>(T)) {
- Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
+ S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
diag::err_trailing_return_without_auto)
<< T << D.getDeclSpec().getSourceRange();
D.setInvalidType(true);
}
- T = GetTypeFromParser(
+ T = S.GetTypeFromParser(
ParsedType::getFromOpaquePtr(FTI.TrailingReturnType),
- &ReturnTypeInfo);
+ &TInfo);
}
}
@@ -1809,7 +2040,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
if (chunkIndex == 0 &&
D.getContext() == Declarator::BlockLiteralContext)
diagID = diag::err_block_returning_array_function;
- Diag(DeclType.Loc, diagID) << T->isFunctionType() << T;
+ S.Diag(DeclType.Loc, diagID) << T->isFunctionType() << T;
T = Context.IntTy;
D.setInvalidType(true);
}
@@ -1818,7 +2049,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// class type in C++.
if (isa<PointerType>(T) && T.getLocalCVRQualifiers() &&
(D.getName().getKind() != UnqualifiedId::IK_ConversionFunctionId) &&
- (!getLangOptions().CPlusPlus || !T->isDependentType())) {
+ (!LangOpts.CPlusPlus || !T->isDependentType())) {
assert(chunkIndex + 1 < e && "No DeclaratorChunk for the return type?");
DeclaratorChunk ReturnTypeChunk = D.getTypeObject(chunkIndex + 1);
assert(ReturnTypeChunk.Kind == DeclaratorChunk::Pointer);
@@ -1829,43 +2060,43 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
SourceLocation::getFromRawEncoding(PTI.ConstQualLoc),
SourceLocation::getFromRawEncoding(PTI.VolatileQualLoc),
SourceLocation::getFromRawEncoding(PTI.RestrictQualLoc),
- *this);
+ S);
} else if (T.getCVRQualifiers() && D.getDeclSpec().getTypeQualifiers() &&
- (!getLangOptions().CPlusPlus ||
+ (!LangOpts.CPlusPlus ||
(!T->isDependentType() && !T->isRecordType()))) {
DiagnoseIgnoredQualifiers(D.getDeclSpec().getTypeQualifiers(),
D.getDeclSpec().getConstSpecLoc(),
D.getDeclSpec().getVolatileSpecLoc(),
D.getDeclSpec().getRestrictSpecLoc(),
- *this);
+ S);
}
- if (getLangOptions().CPlusPlus && D.getDeclSpec().isTypeSpecOwned()) {
+ if (LangOpts.CPlusPlus && D.getDeclSpec().isTypeSpecOwned()) {
// C++ [dcl.fct]p6:
// Types shall not be defined in return or parameter types.
TagDecl *Tag = cast<TagDecl>(D.getDeclSpec().getRepAsDecl());
if (Tag->isDefinition())
- Diag(Tag->getLocation(), diag::err_type_defined_in_result_type)
+ S.Diag(Tag->getLocation(), diag::err_type_defined_in_result_type)
<< Context.getTypeDeclType(Tag);
}
// Exception specs are not allowed in typedefs. Complain, but add it
// anyway.
if (IsTypedefName && FTI.getExceptionSpecType())
- Diag(FTI.getExceptionSpecLoc(), diag::err_exception_spec_in_typedef)
+ S.Diag(FTI.getExceptionSpecLoc(), diag::err_exception_spec_in_typedef)
<< (D.getContext() == Declarator::AliasDeclContext ||
D.getContext() == Declarator::AliasTemplateContext);
- if (!FTI.NumArgs && !FTI.isVariadic && !getLangOptions().CPlusPlus) {
+ if (!FTI.NumArgs && !FTI.isVariadic && !LangOpts.CPlusPlus) {
// Simple void foo(), where the incoming T is the result type.
T = Context.getFunctionNoProtoType(T);
} else {
// We allow a zero-parameter variadic function in C if the
// function is marked with the "overloadable" attribute. Scan
// for this attribute now.
- if (!FTI.NumArgs && FTI.isVariadic && !getLangOptions().CPlusPlus) {
+ if (!FTI.NumArgs && FTI.isVariadic && !LangOpts.CPlusPlus) {
bool Overloadable = false;
for (const AttributeList *Attrs = D.getAttributes();
Attrs; Attrs = Attrs->getNext()) {
@@ -1876,13 +2107,13 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
}
if (!Overloadable)
- Diag(FTI.getEllipsisLoc(), diag::err_ellipsis_first_arg);
+ S.Diag(FTI.getEllipsisLoc(), diag::err_ellipsis_first_arg);
}
if (FTI.NumArgs && FTI.ArgInfo[0].Param == 0) {
// C99 6.7.5.3p3: Reject int(x,y,z) when it's not a function
// definition.
- Diag(FTI.ArgInfo[0].IdentLoc, diag::err_ident_list_in_fn_declaration);
+ S.Diag(FTI.ArgInfo[0].IdentLoc, diag::err_ident_list_in_fn_declaration);
D.setInvalidType(true);
break;
}
@@ -1899,13 +2130,18 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
llvm::SmallVector<QualType, 16> ArgTys;
ArgTys.reserve(FTI.NumArgs);
+ llvm::SmallVector<bool, 16> ConsumedArguments;
+ ConsumedArguments.reserve(FTI.NumArgs);
+ bool HasAnyConsumedArguments = false;
+
for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) {
ParmVarDecl *Param = cast<ParmVarDecl>(FTI.ArgInfo[i].Param);
QualType ArgTy = Param->getType();
assert(!ArgTy.isNull() && "Couldn't parse type?");
// Adjust the parameter type.
- assert((ArgTy == adjustParameterType(ArgTy)) && "Unadjusted type?");
+ assert((ArgTy == Context.getAdjustedParameterType(ArgTy)) &&
+ "Unadjusted type?");
// Look for 'void'. void is allowed only as a single argument to a
// function with no other parameters (C99 6.7.5.3p10). We record
@@ -1915,19 +2151,19 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// is an incomplete type (C99 6.2.5p19) and function decls cannot
// have arguments of incomplete type.
if (FTI.NumArgs != 1 || FTI.isVariadic) {
- Diag(DeclType.Loc, diag::err_void_only_param);
+ S.Diag(DeclType.Loc, diag::err_void_only_param);
ArgTy = Context.IntTy;
Param->setType(ArgTy);
} else if (FTI.ArgInfo[i].Ident) {
// Reject, but continue to parse 'int(void abc)'.
- Diag(FTI.ArgInfo[i].IdentLoc,
+ S.Diag(FTI.ArgInfo[i].IdentLoc,
diag::err_param_with_void_type);
ArgTy = Context.IntTy;
Param->setType(ArgTy);
} else {
// Reject, but continue to parse 'float(const void)'.
if (ArgTy.hasQualifiers())
- Diag(DeclType.Loc, diag::err_void_param_qualified);
+ S.Diag(DeclType.Loc, diag::err_void_param_qualified);
// Do not add 'void' to the ArgTys list.
break;
@@ -1944,19 +2180,28 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
}
}
+ if (LangOpts.ObjCAutoRefCount) {
+ bool Consumed = Param->hasAttr<NSConsumedAttr>();
+ ConsumedArguments.push_back(Consumed);
+ HasAnyConsumedArguments |= Consumed;
+ }
+
ArgTys.push_back(ArgTy);
}
+ if (HasAnyConsumedArguments)
+ EPI.ConsumedArguments = ConsumedArguments.data();
+
llvm::SmallVector<QualType, 4> Exceptions;
EPI.ExceptionSpecType = FTI.getExceptionSpecType();
if (FTI.getExceptionSpecType() == EST_Dynamic) {
Exceptions.reserve(FTI.NumExceptions);
for (unsigned ei = 0, ee = FTI.NumExceptions; ei != ee; ++ei) {
// FIXME: Preserve type source info.
- QualType ET = GetTypeFromParser(FTI.Exceptions[ei].Ty);
+ QualType ET = S.GetTypeFromParser(FTI.Exceptions[ei].Ty);
// Check that the type is valid for an exception spec, and
// drop it if not.
- if (!CheckSpecifiedExceptionType(ET, FTI.Exceptions[ei].Range))
+ if (!S.CheckSpecifiedExceptionType(ET, FTI.Exceptions[ei].Range))
Exceptions.push_back(ET);
}
EPI.NumExceptions = Exceptions.size();
@@ -1973,7 +2218,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
if (!NoexceptExpr->isValueDependent() &&
!NoexceptExpr->isIntegerConstantExpr(Dummy, Context, &ErrLoc,
/*evaluated*/false))
- Diag(ErrLoc, diag::err_noexcept_needs_constant_expression)
+ S.Diag(ErrLoc, diag::err_noexcept_needs_constant_expression)
<< NoexceptExpr->getSourceRange();
else
EPI.NoexceptExpr = NoexceptExpr;
@@ -1996,8 +2241,8 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
if (SS.isInvalid()) {
// Avoid emitting extra errors if we already errored on the scope.
D.setInvalidType(true);
- } else if (isDependentScopeSpecifier(SS) ||
- dyn_cast_or_null<CXXRecordDecl>(computeDeclContext(SS))) {
+ } else if (S.isDependentScopeSpecifier(SS) ||
+ dyn_cast_or_null<CXXRecordDecl>(S.computeDeclContext(SS))) {
NestedNameSpecifier *NNS
= static_cast<NestedNameSpecifier*>(SS.getScopeRep());
NestedNameSpecifier *NNSPrefix = NNS->getPrefix();
@@ -2026,7 +2271,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
break;
}
} else {
- Diag(DeclType.Mem.Scope().getBeginLoc(),
+ S.Diag(DeclType.Mem.Scope().getBeginLoc(),
diag::err_illegal_decl_mempointer_in_nonclass)
<< (D.getIdentifier() ? D.getIdentifier()->getName() : "type name")
<< DeclType.Mem.Scope().getRange();
@@ -2034,12 +2279,12 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
}
if (!ClsType.isNull())
- T = BuildMemberPointerType(T, ClsType, DeclType.Loc, D.getIdentifier());
+ T = S.BuildMemberPointerType(T, ClsType, DeclType.Loc, D.getIdentifier());
if (T.isNull()) {
T = Context.IntTy;
D.setInvalidType(true);
} else if (DeclType.Mem.TypeQuals) {
- T = BuildQualifiedType(T, DeclType.Loc, DeclType.Mem.TypeQuals);
+ T = S.BuildQualifiedType(T, DeclType.Loc, DeclType.Mem.TypeQuals);
}
break;
}
@@ -2054,7 +2299,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
processTypeAttrs(state, T, false, attrs);
}
- if (getLangOptions().CPlusPlus && T->isFunctionType()) {
+ if (LangOpts.CPlusPlus && T->isFunctionType()) {
const FunctionProtoType *FnTy = T->getAs<FunctionProtoType>();
assert(FnTy && "Why oh why is there not a FunctionProtoType here?");
@@ -2071,7 +2316,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
FreeFunction = (D.getContext() != Declarator::MemberContext ||
D.getDeclSpec().isFriendSpecified());
} else {
- DeclContext *DC = computeDeclContext(D.getCXXScopeSpec());
+ DeclContext *DC = S.computeDeclContext(D.getCXXScopeSpec());
FreeFunction = (DC && !DC->isRecord());
}
@@ -2109,16 +2354,16 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
break;
}
- Diag(D.getIdentifierLoc(),
+ S.Diag(D.getIdentifierLoc(),
diag::ext_qualified_function_type_template_arg)
<< Quals;
} else {
if (FnTy->getTypeQuals() != 0) {
if (D.isFunctionDeclarator())
- Diag(D.getIdentifierLoc(),
+ S.Diag(D.getIdentifierLoc(),
diag::err_invalid_qualified_function_type);
else
- Diag(D.getIdentifierLoc(),
+ S.Diag(D.getIdentifierLoc(),
diag::err_invalid_qualified_typedef_function_type_use)
<< FreeFunction;
}
@@ -2135,11 +2380,11 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
}
}
- Diag(Loc, diag::err_invalid_ref_qualifier_function_type)
+ S.Diag(Loc, diag::err_invalid_ref_qualifier_function_type)
<< (FnTy->getRefQualifier() == RQ_LValue)
<< FixItHint::CreateRemoval(Loc);
} else {
- Diag(D.getIdentifierLoc(),
+ S.Diag(D.getIdentifierLoc(),
diag::err_invalid_ref_qualifier_typedef_function_type_use)
<< FreeFunction
<< (FnTy->getRefQualifier() == RQ_LValue);
@@ -2192,7 +2437,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// We represent function parameter packs as function parameters whose
// type is a pack expansion.
if (!T->containsUnexpandedParameterPack()) {
- Diag(D.getEllipsisLoc(),
+ S.Diag(D.getEllipsisLoc(),
diag::err_function_parameter_pack_without_parameter_packs)
<< T << D.getSourceRange();
D.setEllipsisLoc(SourceLocation());
@@ -2212,14 +2457,15 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// it expands those parameter packs.
if (T->containsUnexpandedParameterPack())
T = Context.getPackExpansionType(T, llvm::Optional<unsigned>());
- else if (!getLangOptions().CPlusPlus0x)
- Diag(D.getEllipsisLoc(), diag::ext_variadic_templates);
+ else if (!LangOpts.CPlusPlus0x)
+ S.Diag(D.getEllipsisLoc(), diag::ext_variadic_templates);
break;
case Declarator::FileContext:
case Declarator::KNRTypeListContext:
case Declarator::ObjCPrototypeContext: // FIXME: special diagnostic here?
case Declarator::TypeNameContext:
+ case Declarator::CXXNewContext:
case Declarator::AliasDeclContext:
case Declarator::AliasTemplateContext:
case Declarator::MemberContext:
@@ -2227,11 +2473,12 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
case Declarator::ForContext:
case Declarator::ConditionContext:
case Declarator::CXXCatchContext:
+ case Declarator::ObjCCatchContext:
case Declarator::BlockLiteralContext:
case Declarator::TemplateTypeArgContext:
// FIXME: We may want to allow parameter packs in block-literal contexts
// in the future.
- Diag(D.getEllipsisLoc(), diag::err_ellipsis_in_declarator_not_parameter);
+ S.Diag(D.getEllipsisLoc(), diag::err_ellipsis_in_declarator_not_parameter);
D.setEllipsisLoc(SourceLocation());
break;
}
@@ -2241,7 +2488,138 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
return Context.getNullTypeSourceInfo();
else if (D.isInvalidType())
return Context.getTrivialTypeSourceInfo(T);
- return GetTypeSourceInfoForDeclarator(D, T, ReturnTypeInfo);
+
+ return S.GetTypeSourceInfoForDeclarator(D, T, TInfo);
+}
+
+/// GetTypeForDeclarator - Convert the type for the specified
+/// declarator to Type instances.
+///
+/// The result of this call will never be null, but the associated
+/// type may be a null type if there's an unrecoverable error.
+TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S) {
+ // Determine the type of the declarator. Not all forms of declarator
+ // have a type.
+
+ TypeProcessingState state(*this, D);
+
+ TypeSourceInfo *ReturnTypeInfo = 0;
+ QualType T = GetDeclSpecTypeForDeclarator(state, ReturnTypeInfo);
+ if (T.isNull())
+ return Context.getNullTypeSourceInfo();
+
+ if (D.isPrototypeContext() && getLangOptions().ObjCAutoRefCount)
+ inferARCWriteback(state, T);
+
+ return GetFullTypeForDeclarator(state, T, ReturnTypeInfo);
+}
+
+static void transferARCOwnershipToDeclSpec(Sema &S,
+ QualType &declSpecTy,
+ Qualifiers::ObjCLifetime ownership) {
+ if (declSpecTy->isObjCRetainableType() &&
+ declSpecTy.getObjCLifetime() == Qualifiers::OCL_None) {
+ Qualifiers qs;
+ qs.addObjCLifetime(ownership);
+ declSpecTy = S.Context.getQualifiedType(declSpecTy, qs);
+ }
+}
+
+static void transferARCOwnershipToDeclaratorChunk(TypeProcessingState &state,
+ Qualifiers::ObjCLifetime ownership,
+ unsigned chunkIndex) {
+ Sema &S = state.getSema();
+ Declarator &D = state.getDeclarator();
+
+ // Look for an explicit lifetime attribute.
+ DeclaratorChunk &chunk = D.getTypeObject(chunkIndex);
+ for (const AttributeList *attr = chunk.getAttrs(); attr;
+ attr = attr->getNext())
+ if (attr->getKind() == AttributeList::AT_objc_ownership)
+ return;
+
+ const char *attrStr = 0;
+ switch (ownership) {
+ case Qualifiers::OCL_None: llvm_unreachable("no ownership!"); break;
+ case Qualifiers::OCL_ExplicitNone: attrStr = "none"; break;
+ case Qualifiers::OCL_Strong: attrStr = "strong"; break;
+ case Qualifiers::OCL_Weak: attrStr = "weak"; break;
+ case Qualifiers::OCL_Autoreleasing: attrStr = "autoreleasing"; break;
+ }
+
+ // If there wasn't one, add one (with an invalid source location
+ // so that we don't make an AttributedType for it).
+ AttributeList *attr = D.getAttributePool()
+ .create(&S.Context.Idents.get("objc_ownership"), SourceLocation(),
+ /*scope*/ 0, SourceLocation(),
+ &S.Context.Idents.get(attrStr), SourceLocation(),
+ /*args*/ 0, 0,
+ /*declspec*/ false, /*C++0x*/ false);
+ spliceAttrIntoList(*attr, chunk.getAttrListRef());
+
+ // TODO: mark whether we did this inference?
+}
+
+static void transferARCOwnership(TypeProcessingState &state,
+ QualType &declSpecTy,
+ Qualifiers::ObjCLifetime ownership) {
+ Sema &S = state.getSema();
+ Declarator &D = state.getDeclarator();
+
+ int inner = -1;
+ for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
+ DeclaratorChunk &chunk = D.getTypeObject(i);
+ switch (chunk.Kind) {
+ case DeclaratorChunk::Paren:
+ // Ignore parens.
+ break;
+
+ case DeclaratorChunk::Array:
+ case DeclaratorChunk::Reference:
+ case DeclaratorChunk::Pointer:
+ inner = i;
+ break;
+
+ case DeclaratorChunk::BlockPointer:
+ return transferARCOwnershipToDeclaratorChunk(state, ownership, i);
+
+ case DeclaratorChunk::Function:
+ case DeclaratorChunk::MemberPointer:
+ return;
+ }
+ }
+
+ if (inner == -1)
+ return transferARCOwnershipToDeclSpec(S, declSpecTy, ownership);
+
+ DeclaratorChunk &chunk = D.getTypeObject(inner);
+ if (chunk.Kind == DeclaratorChunk::Pointer) {
+ if (declSpecTy->isObjCRetainableType())
+ return transferARCOwnershipToDeclSpec(S, declSpecTy, ownership);
+ if (declSpecTy->isObjCObjectType())
+ return transferARCOwnershipToDeclaratorChunk(state, ownership, inner);
+ } else {
+ assert(chunk.Kind == DeclaratorChunk::Array ||
+ chunk.Kind == DeclaratorChunk::Reference);
+ return transferARCOwnershipToDeclSpec(S, declSpecTy, ownership);
+ }
+}
+
+TypeSourceInfo *Sema::GetTypeForDeclaratorCast(Declarator &D, QualType FromTy) {
+ TypeProcessingState state(*this, D);
+
+ TypeSourceInfo *ReturnTypeInfo = 0;
+ QualType declSpecTy = GetDeclSpecTypeForDeclarator(state, ReturnTypeInfo);
+ if (declSpecTy.isNull())
+ return Context.getNullTypeSourceInfo();
+
+ if (getLangOptions().ObjCAutoRefCount) {
+ Qualifiers::ObjCLifetime ownership = Context.getInnerObjCOwnership(FromTy);
+ if (ownership != Qualifiers::OCL_None)
+ transferARCOwnership(state, declSpecTy, ownership);
+ }
+
+ return GetFullTypeForDeclarator(state, declSpecTy, ReturnTypeInfo);
}
/// Map an AttributedType::Kind to an AttributeList::Kind.
@@ -2259,6 +2637,8 @@ static AttributeList::Kind getAttrListKind(AttributedType::Kind kind) {
return AttributeList::AT_neon_polyvector_type;
case AttributedType::attr_objc_gc:
return AttributeList::AT_objc_gc;
+ case AttributedType::attr_objc_ownership:
+ return AttributeList::AT_objc_ownership;
case AttributedType::attr_noreturn:
return AttributeList::AT_noreturn;
case AttributedType::attr_cdecl:
@@ -2489,6 +2869,9 @@ namespace {
llvm_unreachable("qualified type locs not expected here!");
}
+ void VisitAttributedTypeLoc(AttributedTypeLoc TL) {
+ fillAttributedTypeLoc(TL, Chunk.getAttrs());
+ }
void VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) {
assert(Chunk.Kind == DeclaratorChunk::BlockPointer);
TL.setCaretLoc(Chunk.Loc);
@@ -2657,8 +3040,7 @@ TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) {
// the parser.
assert(D.getIdentifier() == 0 && "Type name should have no identifier!");
- TagDecl *OwnedTag = 0;
- TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S, &OwnedTag);
+ TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);
QualType T = TInfo->getType();
if (D.isInvalidType())
return true;
@@ -2666,26 +3048,11 @@ TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) {
if (getLangOptions().CPlusPlus) {
// Check that there are no default arguments (C++ only).
CheckExtraCXXDefaultArguments(D);
-
- // C++0x [dcl.type]p3:
- // A type-specifier-seq shall not define a class or enumeration unless
- // it appears in the type-id of an alias-declaration (7.1.3) that is not
- // the declaration of a template-declaration.
- if (OwnedTag && OwnedTag->isDefinition()) {
- if (D.getContext() == Declarator::AliasTemplateContext)
- Diag(OwnedTag->getLocation(), diag::err_type_defined_in_alias_template)
- << Context.getTypeDeclType(OwnedTag);
- else if (D.getContext() != Declarator::AliasDeclContext)
- Diag(OwnedTag->getLocation(), diag::err_type_defined_in_type_specifier)
- << Context.getTypeDeclType(OwnedTag);
- }
}
return CreateParsedType(T, TInfo);
}
-
-
//===----------------------------------------------------------------------===//
// Type Attribute Processing
//===----------------------------------------------------------------------===//
@@ -2744,6 +3111,99 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type,
Type = S.Context.getAddrSpaceQualType(Type, ASIdx);
}
+/// handleObjCOwnershipTypeAttr - Process an objc_ownership
+/// attribute on the specified type.
+///
+/// Returns 'true' if the attribute was handled.
+static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
+ AttributeList &attr,
+ QualType &type) {
+ if (!type->isObjCRetainableType() && !type->isDependentType())
+ return false;
+
+ Sema &S = state.getSema();
+
+ if (type.getQualifiers().getObjCLifetime()) {
+ S.Diag(attr.getLoc(), diag::err_attr_objc_ownership_redundant)
+ << type;
+ return true;
+ }
+
+ if (!attr.getParameterName()) {
+ S.Diag(attr.getLoc(), diag::err_attribute_argument_n_not_string)
+ << "objc_ownership" << 1;
+ attr.setInvalid();
+ return true;
+ }
+
+ Qualifiers::ObjCLifetime lifetime;
+ if (attr.getParameterName()->isStr("none"))
+ lifetime = Qualifiers::OCL_ExplicitNone;
+ else if (attr.getParameterName()->isStr("strong"))
+ lifetime = Qualifiers::OCL_Strong;
+ else if (attr.getParameterName()->isStr("weak"))
+ lifetime = Qualifiers::OCL_Weak;
+ else if (attr.getParameterName()->isStr("autoreleasing"))
+ lifetime = Qualifiers::OCL_Autoreleasing;
+ else {
+ S.Diag(attr.getLoc(), diag::warn_attribute_type_not_supported)
+ << "objc_ownership" << attr.getParameterName();
+ attr.setInvalid();
+ return true;
+ }
+
+ // Consume lifetime attributes without further comment outside of
+ // ARC mode.
+ if (!S.getLangOptions().ObjCAutoRefCount)
+ return true;
+
+ Qualifiers qs;
+ qs.setObjCLifetime(lifetime);
+ QualType origType = type;
+ type = S.Context.getQualifiedType(type, qs);
+
+ // If we have a valid source location for the attribute, use an
+ // AttributedType instead.
+ if (attr.getLoc().isValid())
+ type = S.Context.getAttributedType(AttributedType::attr_objc_ownership,
+ origType, type);
+
+ // Forbid __weak if the runtime doesn't support it.
+ if (lifetime == Qualifiers::OCL_Weak &&
+ !S.getLangOptions().ObjCRuntimeHasWeak) {
+
+ // Actually, delay this until we know what we're parsing.
+ if (S.DelayedDiagnostics.shouldDelayDiagnostics()) {
+ S.DelayedDiagnostics.add(
+ sema::DelayedDiagnostic::makeForbiddenType(attr.getLoc(),
+ diag::err_arc_weak_no_runtime, type, /*ignored*/ 0));
+ } else {
+ S.Diag(attr.getLoc(), diag::err_arc_weak_no_runtime);
+ }
+
+ attr.setInvalid();
+ return true;
+ }
+
+ // Forbid __weak for class objects marked as
+ // objc_arc_weak_reference_unavailable
+ if (lifetime == Qualifiers::OCL_Weak) {
+ QualType T = type;
+ while (const PointerType *ptr = T->getAs<PointerType>())
+ T = ptr->getPointeeType();
+ if (const ObjCObjectPointerType *ObjT = T->getAs<ObjCObjectPointerType>()) {
+ ObjCInterfaceDecl *Class = ObjT->getInterfaceDecl();
+ if (Class->isArcWeakrefUnavailable()) {
+ S.Diag(attr.getLoc(), diag::err_arc_unsupported_weak_class);
+ S.Diag(ObjT->getInterfaceDecl()->getLocation(),
+ diag::note_class_declared);
+ }
+ }
+ }
+
+ return true;
+}
+
/// handleObjCGCTypeAttr - Process the __attribute__((objc_gc)) type
/// attribute on the specified type. Returns true to indicate that
/// the attribute was handled, false to indicate that the type does
@@ -2954,6 +3414,23 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state,
return true;
}
+ // ns_returns_retained is not always a type attribute, but if we got
+ // here, we're treating it as one right now.
+ if (attr.getKind() == AttributeList::AT_ns_returns_retained) {
+ assert(S.getLangOptions().ObjCAutoRefCount &&
+ "ns_returns_retained treated as type attribute in non-ARC");
+ if (attr.getNumArgs()) return true;
+
+ // Delay if this is not a function type.
+ if (!unwrapped.isFunctionType())
+ return false;
+
+ FunctionType::ExtInfo EI
+ = unwrapped.get()->getExtInfo().withProducesResult(true);
+ type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI));
+ return true;
+ }
+
if (attr.getKind() == AttributeList::AT_regparm) {
unsigned value;
if (S.CheckRegparmAttr(attr, value))
@@ -3127,6 +3604,40 @@ static void HandleVectorSizeAttr(QualType& CurType, const AttributeList &Attr,
VectorType::GenericVector);
}
+/// \brief Process the OpenCL-like ext_vector_type attribute when it occurs on
+/// a type.
+static void HandleExtVectorTypeAttr(QualType &CurType,
+ const AttributeList &Attr,
+ Sema &S) {
+ Expr *sizeExpr;
+
+ // Special case where the argument is a template id.
+ if (Attr.getParameterName()) {
+ CXXScopeSpec SS;
+ UnqualifiedId id;
+ id.setIdentifier(Attr.getParameterName(), Attr.getLoc());
+
+ ExprResult Size = S.ActOnIdExpression(S.getCurScope(), SS, id, false,
+ false);
+ if (Size.isInvalid())
+ return;
+
+ sizeExpr = Size.get();
+ } else {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() != 1) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ return;
+ }
+ sizeExpr = Attr.getArg(0);
+ }
+
+ // Create the vector type.
+ QualType T = S.BuildExtVectorType(CurType, sizeExpr, Attr.getLoc());
+ if (!T.isNull())
+ CurType = T;
+}
+
/// HandleNeonVectorTypeAttr - The "neon_vector_type" and
/// "neon_polyvector_type" attributes are used to create vector types that
/// are mangled according to ARM's ABI. Otherwise, these types are identical
@@ -3217,6 +3728,11 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
case AttributeList::AT_vector_size:
HandleVectorSizeAttr(type, attr, state.getSema());
break;
+ case AttributeList::AT_ext_vector_type:
+ if (state.getDeclarator().getDeclSpec().getStorageClassSpec()
+ != DeclSpec::SCS_typedef)
+ HandleExtVectorTypeAttr(type, attr, state.getSema());
+ break;
case AttributeList::AT_neon_vector_type:
HandleNeonVectorTypeAttr(type, attr, state.getSema(),
VectorType::NeonVector, "neon_vector_type");
@@ -3226,11 +3742,15 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
VectorType::NeonPolyVector,
"neon_polyvector_type");
break;
-
case AttributeList::AT_opencl_image_access:
HandleOpenCLImageAccessAttribute(type, attr, state.getSema());
break;
+ case AttributeList::AT_ns_returns_retained:
+ if (!state.getSema().getLangOptions().ObjCAutoRefCount)
+ break;
+ // fallthrough into the function attrs
+
FUNCTION_TYPE_ATTRS_CASELIST:
// Never process function type attributes as part of the
// declaration-specifiers.
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index ff2e46a9026b..fa87217821aa 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -1192,6 +1192,16 @@ public:
Body);
}
+ /// \brief Build a new Objective-C @autoreleasepool statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ StmtResult RebuildObjCAutoreleasePoolStmt(SourceLocation AtLoc,
+ Stmt *Body) {
+ return getSema().ActOnObjCAutoreleasePoolStmt(AtLoc, Body);
+ }
+
+
/// \brief Build a new Objective-C fast enumeration statement.
///
/// By default, performs semantic analysis to build the new statement.
@@ -1537,9 +1547,9 @@ public:
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
ExprResult RebuildInitList(SourceLocation LBraceLoc,
- MultiExprArg Inits,
- SourceLocation RBraceLoc,
- QualType ResultTy) {
+ MultiExprArg Inits,
+ SourceLocation RBraceLoc,
+ QualType ResultTy) {
ExprResult Result
= SemaRef.ActOnInitList(LBraceLoc, move(Inits), RBraceLoc);
if (Result.isInvalid() || ResultTy->isDependentType())
@@ -1856,8 +1866,9 @@ public:
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
- ExprResult RebuildCXXThrowExpr(SourceLocation ThrowLoc, Expr *Sub) {
- return getSema().ActOnCXXThrow(ThrowLoc, Sub);
+ ExprResult RebuildCXXThrowExpr(SourceLocation ThrowLoc, Expr *Sub,
+ bool IsThrownVariableInScope) {
+ return getSema().BuildCXXThrow(ThrowLoc, Sub, IsThrownVariableInScope);
}
/// \brief Build a new C++ default-argument expression.
@@ -2466,6 +2477,10 @@ bool TreeTransform<Derived>::TransformExprs(Expr **Inputs,
Outputs.push_back(Out.get());
continue;
}
+
+ // Record right away that the argument was changed. This needs
+ // to happen even if the array expands to nothing.
+ if (ArgChanged) *ArgChanged = true;
// The transform has determined that we should perform an elementwise
// expansion of the pattern. Do so.
@@ -2482,8 +2497,6 @@ bool TreeTransform<Derived>::TransformExprs(Expr **Inputs,
return true;
}
- if (ArgChanged)
- *ArgChanged = true;
Outputs.push_back(Out.get());
}
@@ -3162,6 +3175,38 @@ TreeTransform<Derived>::TransformQualifiedType(TypeLocBuilder &TLB,
if (Result->isFunctionType() || Result->isReferenceType())
return Result;
+ // Suppress Objective-C lifetime qualifiers if they don't make sense for the
+ // resulting type.
+ if (Quals.hasObjCLifetime()) {
+ if (!Result->isObjCLifetimeType() && !Result->isDependentType())
+ Quals.removeObjCLifetime();
+ else if (Result.getObjCLifetime()) {
+ // Objective-C ARC:
+ // A lifetime qualifier applied to a substituted template parameter
+ // overrides the lifetime qualifier from the template argument.
+ if (const SubstTemplateTypeParmType *SubstTypeParam
+ = dyn_cast<SubstTemplateTypeParmType>(Result)) {
+ QualType Replacement = SubstTypeParam->getReplacementType();
+ Qualifiers Qs = Replacement.getQualifiers();
+ Qs.removeObjCLifetime();
+ Replacement
+ = SemaRef.Context.getQualifiedType(Replacement.getUnqualifiedType(),
+ Qs);
+ Result = SemaRef.Context.getSubstTemplateTypeParmType(
+ SubstTypeParam->getReplacedParameter(),
+ Replacement);
+ TLB.TypeWasModifiedSafely(Result);
+ } else {
+ // Otherwise, complain about the addition of a qualifier to an
+ // already-qualified type.
+ SourceRange R = TLB.getTemporaryTypeLoc(Result).getSourceRange();
+ SemaRef.Diag(R.getBegin(), diag::err_attr_objc_ownership_redundant)
+ << Result << R;
+
+ Quals.removeObjCLifetime();
+ }
+ }
+ }
if (!Quals.empty()) {
Result = SemaRef.BuildQualifiedType(Result, T.getBeginLoc(), Quals);
TLB.push<QualifiedTypeLoc>(Result);
@@ -3333,7 +3378,11 @@ QualType TreeTransform<Derived>::TransformPointerType(TypeLocBuilder &TLB,
if (Result.isNull())
return QualType();
}
-
+
+ // Objective-C ARC can add lifetime qualifiers to the type that we're
+ // pointing to.
+ TLB.TypeWasModifiedSafely(Result->getPointeeType());
+
PointerTypeLoc NewT = TLB.push<PointerTypeLoc>(Result);
NewT.setSigilLoc(TL.getSigilLoc());
return Result;
@@ -3387,6 +3436,11 @@ TreeTransform<Derived>::TransformReferenceType(TypeLocBuilder &TLB,
return QualType();
}
+ // Objective-C ARC can add lifetime qualifiers to the type that we're
+ // referring to.
+ TLB.TypeWasModifiedSafely(
+ Result->getAs<ReferenceType>()->getPointeeTypeAsWritten());
+
// r-value references can be rebuilt as l-value references.
ReferenceTypeLoc NewTL;
if (isa<LValueReferenceType>(Result))
@@ -5435,6 +5489,25 @@ TreeTransform<Derived>::TransformObjCAtSynchronizedStmt(
template<typename Derived>
StmtResult
+TreeTransform<Derived>::TransformObjCAutoreleasePoolStmt(
+ ObjCAutoreleasePoolStmt *S) {
+ // Transform the body.
+ StmtResult Body = getDerived().TransformStmt(S->getSubStmt());
+ if (Body.isInvalid())
+ return StmtError();
+
+ // If nothing changed, just retain this statement.
+ if (!getDerived().AlwaysRebuild() &&
+ Body.get() == S->getSubStmt())
+ return SemaRef.Owned(S);
+
+ // Build a new statement.
+ return getDerived().RebuildObjCAutoreleasePoolStmt(
+ S->getAtLoc(), Body.get());
+}
+
+template<typename Derived>
+StmtResult
TreeTransform<Derived>::TransformObjCForCollectionStmt(
ObjCForCollectionStmt *S) {
// Transform the element statement.
@@ -6721,7 +6794,8 @@ TreeTransform<Derived>::TransformCXXThrowExpr(CXXThrowExpr *E) {
SubExpr.get() == E->getSubExpr())
return SemaRef.Owned(E);
- return getDerived().RebuildCXXThrowExpr(E->getThrowLoc(), SubExpr.get());
+ return getDerived().RebuildCXXThrowExpr(E->getThrowLoc(), SubExpr.get(),
+ E->isThrownVariableInScope());
}
template<typename Derived>
@@ -6867,9 +6941,13 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
AllocType,
AllocTypeInfo,
ArraySize.get(),
- /*FIXME:*/E->getLocStart(),
+ /*FIXME:*/E->hasInitializer()
+ ? E->getLocStart()
+ : SourceLocation(),
move_arg(ConstructorArgs),
- E->getLocEnd());
+ /*FIXME:*/E->hasInitializer()
+ ? E->getLocEnd()
+ : SourceLocation());
}
template<typename Derived>
@@ -7587,6 +7665,21 @@ TreeTransform<Derived>::TransformSubstNonTypeTemplateParmPackExpr(
template<typename Derived>
ExprResult
+TreeTransform<Derived>::TransformSubstNonTypeTemplateParmExpr(
+ SubstNonTypeTemplateParmExpr *E) {
+ // Default behavior is to do nothing with this transformation.
+ return SemaRef.Owned(E);
+}
+
+template<typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformMaterializeTemporaryExpr(
+ MaterializeTemporaryExpr *E) {
+ return getDerived().TransformExpr(E->GetTemporaryExpr());
+}
+
+template<typename Derived>
+ExprResult
TreeTransform<Derived>::TransformObjCStringLiteral(ObjCStringLiteral *E) {
return SemaRef.Owned(E);
}
@@ -7609,6 +7702,43 @@ TreeTransform<Derived>::TransformObjCEncodeExpr(ObjCEncodeExpr *E) {
}
template<typename Derived>
+ExprResult TreeTransform<Derived>::
+TransformObjCIndirectCopyRestoreExpr(ObjCIndirectCopyRestoreExpr *E) {
+ ExprResult result = getDerived().TransformExpr(E->getSubExpr());
+ if (result.isInvalid()) return ExprError();
+ Expr *subExpr = result.take();
+
+ if (!getDerived().AlwaysRebuild() &&
+ subExpr == E->getSubExpr())
+ return SemaRef.Owned(E);
+
+ return SemaRef.Owned(new(SemaRef.Context)
+ ObjCIndirectCopyRestoreExpr(subExpr, E->getType(), E->shouldCopy()));
+}
+
+template<typename Derived>
+ExprResult TreeTransform<Derived>::
+TransformObjCBridgedCastExpr(ObjCBridgedCastExpr *E) {
+ TypeSourceInfo *TSInfo
+ = getDerived().TransformType(E->getTypeInfoAsWritten());
+ if (!TSInfo)
+ return ExprError();
+
+ ExprResult Result = getDerived().TransformExpr(E->getSubExpr());
+ if (Result.isInvalid())
+ return ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ TSInfo == E->getTypeInfoAsWritten() &&
+ Result.get() == E->getSubExpr())
+ return SemaRef.Owned(E);
+
+ return SemaRef.BuildObjCBridgedCast(E->getLParenLoc(), E->getBridgeKind(),
+ E->getBridgeKeywordLoc(), TSInfo,
+ Result.get());
+}
+
+template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) {
// Transform arguments.
@@ -8227,11 +8357,24 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
return SemaRef.CreateOverloadedUnaryOp(OpLoc, Opc, Functions, First);
}
- if (Op == OO_Subscript)
- return SemaRef.CreateOverloadedArraySubscriptExpr(Callee->getLocStart(),
- OpLoc,
- First,
- Second);
+ if (Op == OO_Subscript) {
+ SourceLocation LBrace;
+ SourceLocation RBrace;
+
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Callee)) {
+ DeclarationNameLoc &NameLoc = DRE->getNameInfo().getInfo();
+ LBrace = SourceLocation::getFromRawEncoding(
+ NameLoc.CXXOperatorName.BeginOpNameLoc);
+ RBrace = SourceLocation::getFromRawEncoding(
+ NameLoc.CXXOperatorName.EndOpNameLoc);
+ } else {
+ LBrace = Callee->getLocStart();
+ RBrace = OpLoc;
+ }
+
+ return SemaRef.CreateOverloadedArraySubscriptExpr(LBrace, RBrace,
+ First, Second);
+ }
// Create the overloaded operator invocation for binary operators.
BinaryOperatorKind Opc = BinaryOperator::getOverloadedOpcode(Op);
diff --git a/lib/Sema/TypeLocBuilder.h b/lib/Sema/TypeLocBuilder.h
index 3570737d11bc..7a5e43e25dc9 100644
--- a/lib/Sema/TypeLocBuilder.h
+++ b/lib/Sema/TypeLocBuilder.h
@@ -16,7 +16,6 @@
#define LLVM_CLANG_SEMA_TYPELOCBUILDER_H
#include "clang/AST/TypeLoc.h"
-#include "llvm/ADT/SmallVector.h"
#include "clang/AST/ASTContext.h"
namespace clang {
@@ -87,6 +86,14 @@ class TypeLocBuilder {
Index = Capacity;
}
+ /// \brief Tell the TypeLocBuilder that the type it is storing has been
+ /// modified in some safe way that doesn't affect type-location information.
+ void TypeWasModifiedSafely(QualType T) {
+#ifndef NDEBUG
+ LastTy = T;
+#endif
+ }
+
/// Pushes space for a new TypeLoc of the given type. Invalidates
/// any TypeLocs previously retrieved from this builder.
template <class TyLocType> TyLocType push(QualType T) {
@@ -139,7 +146,7 @@ private:
Index -= LocalSize;
- return getTypeLoc(T);
+ return getTemporaryTypeLoc(T);
}
/// Grow to the given capacity.
@@ -171,15 +178,17 @@ private:
reserve(Size);
Index -= Size;
- return getTypeLoc(T);
+ return getTemporaryTypeLoc(T);
}
-
- // This is private because, when we kill off TypeSourceInfo in favor
- // of TypeLoc, we'll want an interface that creates a TypeLoc given
- // an ASTContext, and we don't want people to think they can just
- // use this as an equivalent.
- TypeLoc getTypeLoc(QualType T) {
+public:
+ /// \brief Retrieve a temporary TypeLoc that refers into this \c TypeLocBuilder
+ /// object.
+ ///
+ /// The resulting \c TypeLoc should only be used so long as the
+ /// \c TypeLocBuilder is active and has not had more type information
+ /// pushed into it.
+ TypeLoc getTemporaryTypeLoc(QualType T) {
#ifndef NDEBUG
assert(LastTy == T && "type doesn't match last type pushed!");
#endif
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index 8fb20d22b7de..a4ed5f4da48c 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -147,9 +147,11 @@ PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) {
PARSE_LANGOPT_IMPORTANT(OpenCL, diag::warn_pch_opencl);
PARSE_LANGOPT_IMPORTANT(CUDA, diag::warn_pch_cuda);
PARSE_LANGOPT_BENIGN(CatchUndefined);
+ PARSE_LANGOPT_BENIGN(DefaultFPContract);
PARSE_LANGOPT_IMPORTANT(ElideConstructors, diag::warn_pch_elide_constructors);
PARSE_LANGOPT_BENIGN(SpellChecking);
- PARSE_LANGOPT_BENIGN(DefaultFPContract);
+ PARSE_LANGOPT_IMPORTANT(ObjCAutoRefCount, diag::warn_pch_auto_ref_count);
+ PARSE_LANGOPT_BENIGN(ObjCInferRelatedReturnType);
#undef PARSE_LANGOPT_IMPORTANT
#undef PARSE_LANGOPT_BENIGN
@@ -655,7 +657,8 @@ public:
// and associate it with the persistent ID.
IdentifierInfo *II = KnownII;
if (!II)
- II = &Reader.getIdentifierTable().getOwn(k.first, k.first + k.second);
+ II = &Reader.getIdentifierTable().getOwn(llvm::StringRef(k.first,
+ k.second));
Reader.SetIdentifierInfo(ID, II);
II->setIsFromAST();
return II;
@@ -682,7 +685,8 @@ public:
// the new IdentifierInfo.
IdentifierInfo *II = KnownII;
if (!II)
- II = &Reader.getIdentifierTable().getOwn(k.first, k.first + k.second);
+ II = &Reader.getIdentifierTable().getOwn(llvm::StringRef(k.first,
+ k.second));
Reader.SetIdentifierInfo(ID, II);
// Set or check the various bits in the IdentifierInfo structure.
@@ -999,8 +1003,7 @@ bool ASTReader::ParseLineTable(PerFileData &F,
std::string Filename(&Record[Idx], &Record[Idx] + FilenameLen);
Idx += FilenameLen;
MaybeAddSystemRootToFilename(Filename);
- FileIDs[I] = LineTable.getLineTableFilenameID(Filename.c_str(),
- Filename.size());
+ FileIDs[I] = LineTable.getLineTableFilenameID(Filename);
}
// Parse the line entries
@@ -1192,7 +1195,7 @@ ASTReader::ASTReadResult ASTReader::ReadSourceManagerBlock(PerFileData &F) {
case SM_SLOC_FILE_ENTRY:
case SM_SLOC_BUFFER_ENTRY:
- case SM_SLOC_INSTANTIATION_ENTRY:
+ case SM_SLOC_EXPANSION_ENTRY:
// Once we hit one of the source location entries, we're done.
return Success;
}
@@ -1362,7 +1365,7 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(unsigned ID) {
break;
}
- case SM_SLOC_INSTANTIATION_ENTRY: {
+ case SM_SLOC_EXPANSION_ENTRY: {
SourceLocation SpellingLoc = ReadSourceLocation(*F, Record[1]);
SourceMgr.createInstantiationLoc(SpellingLoc,
ReadSourceLocation(*F, Record[2]),
@@ -1553,17 +1556,17 @@ PreprocessedEntity *ASTReader::LoadPreprocessedEntity(PerFileData &F) {
(PreprocessorDetailRecordTypes)F.PreprocessorDetailCursor.ReadRecord(
Code, Record, BlobStart, BlobLen);
switch (RecType) {
- case PPD_MACRO_INSTANTIATION: {
+ case PPD_MACRO_EXPANSION: {
if (PreprocessedEntity *PE = PPRec.getPreprocessedEntity(Record[0]))
return PE;
- MacroInstantiation *MI
- = new (PPRec) MacroInstantiation(DecodeIdentifierInfo(Record[3]),
+ MacroExpansion *ME =
+ new (PPRec) MacroExpansion(DecodeIdentifierInfo(Record[3]),
SourceRange(ReadSourceLocation(F, Record[1]),
ReadSourceLocation(F, Record[2])),
- getMacroDefinition(Record[4]));
- PPRec.SetPreallocatedEntity(Record[0], MI);
- return MI;
+ getMacroDefinition(Record[4]));
+ PPRec.SetPreallocatedEntity(Record[0], ME);
+ return ME;
}
case PPD_MACRO_DEFINITION: {
@@ -2366,6 +2369,15 @@ ASTReader::ReadASTBlock(PerFileData &F) {
TentativeDefinitions.insert(TentativeDefinitions.end(),
Record.begin(), Record.end());
break;
+
+ case KNOWN_NAMESPACES:
+ // Optimization for the first block.
+ if (KnownNamespaces.empty())
+ KnownNamespaces.swap(Record);
+ else
+ KnownNamespaces.insert(KnownNamespaces.end(),
+ Record.begin(), Record.end());
+ break;
}
First = false;
}
@@ -2980,6 +2992,7 @@ bool ASTReader::ParseLanguageOptions(
PARSE_LANGOPT(ElideConstructors);
PARSE_LANGOPT(SpellChecking);
PARSE_LANGOPT(MRTD);
+ PARSE_LANGOPT(ObjCAutoRefCount);
#undef PARSE_LANGOPT
return Listener->ReadLanguageOptions(LangOpts);
@@ -3225,12 +3238,13 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) {
}
case TYPE_FUNCTION_NO_PROTO: {
- if (Record.size() != 5) {
+ if (Record.size() != 6) {
Error("incorrect encoding of no-proto function type");
return QualType();
}
QualType ResultType = GetType(Record[0]);
- FunctionType::ExtInfo Info(Record[1], Record[2], Record[3], (CallingConv)Record[4]);
+ FunctionType::ExtInfo Info(Record[1], Record[2], Record[3],
+ (CallingConv)Record[4], Record[5]);
return Context->getFunctionNoProtoType(ResultType, Info);
}
@@ -3241,9 +3255,10 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) {
EPI.ExtInfo = FunctionType::ExtInfo(/*noreturn*/ Record[1],
/*hasregparm*/ Record[2],
/*regparm*/ Record[3],
- static_cast<CallingConv>(Record[4]));
+ static_cast<CallingConv>(Record[4]),
+ /*produces*/ Record[5]);
- unsigned Idx = 5;
+ unsigned Idx = 6;
unsigned NumParams = Record[Idx++];
llvm::SmallVector<QualType, 16> ParamTypes;
for (unsigned I = 0; I != NumParams; ++I)
@@ -3993,12 +4008,9 @@ Stmt *ASTReader::GetExternalDeclStmt(uint64_t Offset) {
llvm_unreachable("Broken chain");
}
-bool ASTReader::FindExternalLexicalDecls(const DeclContext *DC,
+ExternalLoadResult ASTReader::FindExternalLexicalDecls(const DeclContext *DC,
bool (*isKindWeWant)(Decl::Kind),
llvm::SmallVectorImpl<Decl*> &Decls) {
- assert(DC->hasExternalLexicalStorage() &&
- "DeclContext has no lexical decls in storage");
-
// There might be lexical decls in multiple parts of the chain, for the TU
// at least.
// DeclContextOffsets might reallocate as we load additional decls below,
@@ -4023,7 +4035,7 @@ bool ASTReader::FindExternalLexicalDecls(const DeclContext *DC,
}
++NumLexicalDeclContextsRead;
- return false;
+ return ELR_Success;
}
DeclContext::lookup_result
@@ -4446,6 +4458,17 @@ ASTReader::ReadMethodPool(Selector Sel) {
return std::pair<ObjCMethodList, ObjCMethodList>();
}
+void ASTReader::ReadKnownNamespaces(
+ llvm::SmallVectorImpl<NamespaceDecl *> &Namespaces) {
+ Namespaces.clear();
+
+ for (unsigned I = 0, N = KnownNamespaces.size(); I != N; ++I) {
+ if (NamespaceDecl *Namespace
+ = dyn_cast_or_null<NamespaceDecl>(GetDecl(KnownNamespaces[I])))
+ Namespaces.push_back(Namespace);
+ }
+}
+
void ASTReader::LoadSelector(Selector Sel) {
// It would be complicated to avoid reading the methods anyway. So don't.
ReadMethodPool(Sel);
@@ -4540,7 +4563,7 @@ IdentifierInfo *ASTReader::DecodeIdentifierInfo(unsigned ID) {
unsigned StrLen = (((unsigned) StrLenPtr[0])
| (((unsigned) StrLenPtr[1]) << 8)) - 1;
IdentifiersLoaded[ID]
- = &PP->getIdentifierTable().get(Str, StrLen);
+ = &PP->getIdentifierTable().get(llvm::StringRef(Str, StrLen));
if (DeserializationListener)
DeserializationListener->IdentifierRead(ID + 1, IdentifiersLoaded[ID]);
}
@@ -4716,6 +4739,14 @@ ASTReader::ReadTemplateName(PerFileData &F, const RecordData &Record,
return Context->getDependentTemplateName(NNS,
(OverloadedOperatorKind)Record[Idx++]);
}
+
+ case TemplateName::SubstTemplateTemplateParm: {
+ TemplateTemplateParmDecl *param
+ = cast_or_null<TemplateTemplateParmDecl>(GetDecl(Record[Idx++]));
+ if (!param) return TemplateName();
+ TemplateName replacement = ReadTemplateName(F, Record, Idx);
+ return Context->getSubstTemplateTemplateParm(param, replacement);
+ }
case TemplateName::SubstTemplateTemplateParmPack: {
TemplateTemplateParmDecl *Param
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index fab2069bc5f4..24ab544dcd1c 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -710,6 +710,7 @@ void ASTDeclReader::VisitVarDecl(VarDecl *VD) {
VD->VarDeclBits.ExceptionVar = Record[Idx++];
VD->VarDeclBits.NRVOVariable = Record[Idx++];
VD->VarDeclBits.CXXForRangeDecl = Record[Idx++];
+ VD->VarDeclBits.ARCPseudoStrong = Record[Idx++];
if (Record[Idx++])
VD->setInit(Reader.ReadExpr(F));
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index f3f67a76c4d4..14927b9e3bc8 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -60,136 +60,16 @@ namespace clang {
/// \brief The number of record fields required for the Expr class
/// itself.
- static const unsigned NumExprFields = NumStmtFields + 6;
+ static const unsigned NumExprFields = NumStmtFields + 7;
/// \brief Read and initialize a ExplicitTemplateArgumentList structure.
void ReadExplicitTemplateArgumentList(ExplicitTemplateArgumentList &ArgList,
unsigned NumTemplateArgs);
void VisitStmt(Stmt *S);
- void VisitNullStmt(NullStmt *S);
- void VisitCompoundStmt(CompoundStmt *S);
- void VisitSwitchCase(SwitchCase *S);
- void VisitCaseStmt(CaseStmt *S);
- void VisitDefaultStmt(DefaultStmt *S);
- void VisitLabelStmt(LabelStmt *S);
- void VisitIfStmt(IfStmt *S);
- void VisitSwitchStmt(SwitchStmt *S);
- void VisitWhileStmt(WhileStmt *S);
- void VisitDoStmt(DoStmt *S);
- void VisitForStmt(ForStmt *S);
- void VisitGotoStmt(GotoStmt *S);
- void VisitIndirectGotoStmt(IndirectGotoStmt *S);
- void VisitContinueStmt(ContinueStmt *S);
- void VisitBreakStmt(BreakStmt *S);
- void VisitReturnStmt(ReturnStmt *S);
- void VisitDeclStmt(DeclStmt *S);
- void VisitAsmStmt(AsmStmt *S);
- void VisitExpr(Expr *E);
- void VisitPredefinedExpr(PredefinedExpr *E);
- void VisitDeclRefExpr(DeclRefExpr *E);
- void VisitIntegerLiteral(IntegerLiteral *E);
- void VisitFloatingLiteral(FloatingLiteral *E);
- void VisitImaginaryLiteral(ImaginaryLiteral *E);
- void VisitStringLiteral(StringLiteral *E);
- void VisitCharacterLiteral(CharacterLiteral *E);
- void VisitParenExpr(ParenExpr *E);
- void VisitParenListExpr(ParenListExpr *E);
- void VisitUnaryOperator(UnaryOperator *E);
- void VisitOffsetOfExpr(OffsetOfExpr *E);
- void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E);
- void VisitArraySubscriptExpr(ArraySubscriptExpr *E);
- void VisitCallExpr(CallExpr *E);
- void VisitMemberExpr(MemberExpr *E);
- void VisitCastExpr(CastExpr *E);
- void VisitBinaryOperator(BinaryOperator *E);
- void VisitCompoundAssignOperator(CompoundAssignOperator *E);
- void VisitConditionalOperator(ConditionalOperator *E);
- void VisitBinaryConditionalOperator(BinaryConditionalOperator *E);
- void VisitImplicitCastExpr(ImplicitCastExpr *E);
- void VisitExplicitCastExpr(ExplicitCastExpr *E);
- void VisitCStyleCastExpr(CStyleCastExpr *E);
- void VisitCompoundLiteralExpr(CompoundLiteralExpr *E);
- void VisitExtVectorElementExpr(ExtVectorElementExpr *E);
- void VisitInitListExpr(InitListExpr *E);
- void VisitDesignatedInitExpr(DesignatedInitExpr *E);
- void VisitImplicitValueInitExpr(ImplicitValueInitExpr *E);
- void VisitVAArgExpr(VAArgExpr *E);
- void VisitAddrLabelExpr(AddrLabelExpr *E);
- void VisitStmtExpr(StmtExpr *E);
- void VisitChooseExpr(ChooseExpr *E);
- void VisitGNUNullExpr(GNUNullExpr *E);
- void VisitShuffleVectorExpr(ShuffleVectorExpr *E);
- void VisitBlockExpr(BlockExpr *E);
- void VisitBlockDeclRefExpr(BlockDeclRefExpr *E);
- void VisitGenericSelectionExpr(GenericSelectionExpr *E);
- void VisitObjCStringLiteral(ObjCStringLiteral *E);
- void VisitObjCEncodeExpr(ObjCEncodeExpr *E);
- void VisitObjCSelectorExpr(ObjCSelectorExpr *E);
- void VisitObjCProtocolExpr(ObjCProtocolExpr *E);
- void VisitObjCIvarRefExpr(ObjCIvarRefExpr *E);
- void VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E);
- void VisitObjCMessageExpr(ObjCMessageExpr *E);
- void VisitObjCIsaExpr(ObjCIsaExpr *E);
-
- void VisitObjCForCollectionStmt(ObjCForCollectionStmt *);
- void VisitObjCAtCatchStmt(ObjCAtCatchStmt *);
- void VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *);
- void VisitObjCAtTryStmt(ObjCAtTryStmt *);
- void VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *);
- void VisitObjCAtThrowStmt(ObjCAtThrowStmt *);
-
- // C++ Statements
- void VisitCXXCatchStmt(CXXCatchStmt *S);
- void VisitCXXTryStmt(CXXTryStmt *S);
- void VisitCXXForRangeStmt(CXXForRangeStmt *);
-
- void VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E);
- void VisitCXXConstructExpr(CXXConstructExpr *E);
- void VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E);
- void VisitCXXNamedCastExpr(CXXNamedCastExpr *E);
- void VisitCXXStaticCastExpr(CXXStaticCastExpr *E);
- void VisitCXXDynamicCastExpr(CXXDynamicCastExpr *E);
- void VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *E);
- void VisitCXXConstCastExpr(CXXConstCastExpr *E);
- void VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E);
- void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E);
- void VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E);
- void VisitCXXTypeidExpr(CXXTypeidExpr *E);
- void VisitCXXUuidofExpr(CXXUuidofExpr *E);
- void VisitCXXThisExpr(CXXThisExpr *E);
- void VisitCXXThrowExpr(CXXThrowExpr *E);
- void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E);
- void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E);
-
- void VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E);
- void VisitCXXNewExpr(CXXNewExpr *E);
- void VisitCXXDeleteExpr(CXXDeleteExpr *E);
- void VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E);
-
- void VisitExprWithCleanups(ExprWithCleanups *E);
-
- void VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E);
- void VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E);
- void VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *E);
-
- void VisitOverloadExpr(OverloadExpr *E);
- void VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E);
- void VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E);
-
- void VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E);
- void VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E);
- void VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E);
- void VisitExpressionTraitExpr(ExpressionTraitExpr *E);
- void VisitCXXNoexceptExpr(CXXNoexceptExpr *E);
- void VisitPackExpansionExpr(PackExpansionExpr *E);
- void VisitSizeOfPackExpr(SizeOfPackExpr *E);
- void VisitSubstNonTypeTemplateParmPackExpr(
- SubstNonTypeTemplateParmPackExpr *E);
- void VisitOpaqueValueExpr(OpaqueValueExpr *E);
-
- // CUDA Expressions
- void VisitCUDAKernelCallExpr(CUDAKernelCallExpr *E);
+#define STMT(Type, Base) \
+ void Visit##Type(Type *);
+#include "clang/AST/StmtNodes.inc"
};
}
@@ -410,6 +290,7 @@ void ASTStmtReader::VisitExpr(Expr *E) {
E->setType(Reader.GetType(Record[Idx++]));
E->setTypeDependent(Record[Idx++]);
E->setValueDependent(Record[Idx++]);
+ E->setInstantiationDependent(Record[Idx++]);
E->ExprBits.ContainsUnexpandedParameterPack = Record[Idx++];
E->setValueKind(static_cast<ExprValueKind>(Record[Idx++]));
E->setObjectKind(static_cast<ExprObjectKind>(Record[Idx++]));
@@ -589,6 +470,10 @@ void ASTStmtReader::VisitCallExpr(CallExpr *E) {
E->setArg(I, Reader.ReadSubExpr());
}
+void ASTStmtReader::VisitCXXMemberCallExpr(CXXMemberCallExpr *E) {
+ VisitCallExpr(E);
+}
+
void ASTStmtReader::VisitMemberExpr(MemberExpr *E) {
// Don't call VisitExpr, this is fully initialized at creation.
assert(E->getStmtClass() == Stmt::MemberExprClass &&
@@ -602,6 +487,20 @@ void ASTStmtReader::VisitObjCIsaExpr(ObjCIsaExpr *E) {
E->setArrow(Record[Idx++]);
}
+void ASTStmtReader::
+VisitObjCIndirectCopyRestoreExpr(ObjCIndirectCopyRestoreExpr *E) {
+ VisitExpr(E);
+ E->Operand = Reader.ReadSubExpr();
+ E->setShouldCopy(Record[Idx++]);
+}
+
+void ASTStmtReader::VisitObjCBridgedCastExpr(ObjCBridgedCastExpr *E) {
+ VisitExplicitCastExpr(E);
+ E->LParenLoc = ReadSourceLocation(Record, Idx);
+ E->BridgeKeywordLoc = ReadSourceLocation(Record, Idx);
+ E->Kind = Record[Idx++];
+}
+
void ASTStmtReader::VisitCastExpr(CastExpr *E) {
VisitExpr(E);
unsigned NumBaseSpecs = Record[Idx++];
@@ -929,6 +828,7 @@ void ASTStmtReader::VisitObjCMessageExpr(ObjCMessageExpr *E) {
VisitExpr(E);
assert(Record[Idx] == E->getNumArgs());
++Idx;
+ E->setDelegateInitCall(Record[Idx++]);
ObjCMessageExpr::ReceiverKind Kind
= static_cast<ObjCMessageExpr::ReceiverKind>(Record[Idx++]);
switch (Kind) {
@@ -987,6 +887,12 @@ void ASTStmtReader::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *S) {
S->setAtFinallyLoc(ReadSourceLocation(Record, Idx));
}
+void ASTStmtReader::VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S) {
+ VisitStmt(S);
+ S->setSubStmt(Reader.ReadSubStmt());
+ S->setAtLoc(ReadSourceLocation(Record, Idx));
+}
+
void ASTStmtReader::VisitObjCAtTryStmt(ObjCAtTryStmt *S) {
VisitStmt(S);
assert(Record[Idx] == S->getNumCatchStmts());
@@ -1125,18 +1031,6 @@ void ASTStmtReader::VisitCXXTypeidExpr(CXXTypeidExpr *E) {
// typeid(42+2)
E->setExprOperand(Reader.ReadSubExpr());
}
-void ASTStmtReader::VisitCXXUuidofExpr(CXXUuidofExpr *E) {
- VisitExpr(E);
- E->setSourceRange(ReadSourceRange(Record, Idx));
- if (E->isTypeOperand()) { // __uuidof(ComType)
- E->setTypeOperandSourceInfo(
- GetTypeSourceInfo(Record, Idx));
- return;
- }
-
- // __uuidof(expr)
- E->setExprOperand(Reader.ReadSubExpr());
-}
void ASTStmtReader::VisitCXXThisExpr(CXXThisExpr *E) {
VisitExpr(E);
@@ -1146,8 +1040,9 @@ void ASTStmtReader::VisitCXXThisExpr(CXXThisExpr *E) {
void ASTStmtReader::VisitCXXThrowExpr(CXXThrowExpr *E) {
VisitExpr(E);
- E->setThrowLoc(ReadSourceLocation(Record, Idx));
- E->setSubExpr(Reader.ReadSubExpr());
+ E->ThrowLoc = ReadSourceLocation(Record, Idx);
+ E->Op = Reader.ReadSubExpr();
+ E->IsThrownVariableInScope = Record[Idx++];
}
void ASTStmtReader::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
@@ -1388,6 +1283,15 @@ void ASTStmtReader::VisitSizeOfPackExpr(SizeOfPackExpr *E) {
E->Pack = cast_or_null<NamedDecl>(Reader.GetDecl(Record[Idx++]));
}
+void ASTStmtReader::VisitSubstNonTypeTemplateParmExpr(
+ SubstNonTypeTemplateParmExpr *E) {
+ VisitExpr(E);
+ E->Param
+ = cast_or_null<NonTypeTemplateParmDecl>(Reader.GetDecl(Record[Idx++]));
+ E->NameLoc = ReadSourceLocation(Record, Idx);
+ E->Replacement = Reader.ReadSubExpr();
+}
+
void ASTStmtReader::VisitSubstNonTypeTemplateParmPackExpr(
SubstNonTypeTemplateParmPackExpr *E) {
VisitExpr(E);
@@ -1402,6 +1306,11 @@ void ASTStmtReader::VisitSubstNonTypeTemplateParmPackExpr(
E->NameLoc = ReadSourceLocation(Record, Idx);
}
+void ASTStmtReader::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) {
+ VisitExpr(E);
+ E->Temporary = Reader.ReadSubExpr();
+}
+
void ASTStmtReader::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
VisitExpr(E);
Idx++; // skip ID
@@ -1409,6 +1318,43 @@ void ASTStmtReader::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
}
//===----------------------------------------------------------------------===//
+// Microsoft Expressions and Statements
+//===----------------------------------------------------------------------===//
+void ASTStmtReader::VisitCXXUuidofExpr(CXXUuidofExpr *E) {
+ VisitExpr(E);
+ E->setSourceRange(ReadSourceRange(Record, Idx));
+ if (E->isTypeOperand()) { // __uuidof(ComType)
+ E->setTypeOperandSourceInfo(
+ GetTypeSourceInfo(Record, Idx));
+ return;
+ }
+
+ // __uuidof(expr)
+ E->setExprOperand(Reader.ReadSubExpr());
+}
+
+void ASTStmtReader::VisitSEHExceptStmt(SEHExceptStmt *S) {
+ VisitStmt(S);
+ S->Loc = ReadSourceLocation(Record, Idx);
+ S->Children[SEHExceptStmt::FILTER_EXPR] = Reader.ReadSubStmt();
+ S->Children[SEHExceptStmt::BLOCK] = Reader.ReadSubStmt();
+}
+
+void ASTStmtReader::VisitSEHFinallyStmt(SEHFinallyStmt *S) {
+ VisitStmt(S);
+ S->Loc = ReadSourceLocation(Record, Idx);
+ S->Block = Reader.ReadSubStmt();
+}
+
+void ASTStmtReader::VisitSEHTryStmt(SEHTryStmt *S) {
+ VisitStmt(S);
+ S->IsCXXTry = Record[Idx++];
+ S->TryLoc = ReadSourceLocation(Record, Idx);
+ S->Children[SEHTryStmt::TRY] = Reader.ReadSubStmt();
+ S->Children[SEHTryStmt::HANDLER] = Reader.ReadSubStmt();
+}
+
+//===----------------------------------------------------------------------===//
// CUDA Expressions and Statements
//===----------------------------------------------------------------------===//
@@ -1417,6 +1363,20 @@ void ASTStmtReader::VisitCUDAKernelCallExpr(CUDAKernelCallExpr *E) {
E->setConfig(cast<CallExpr>(Reader.ReadSubExpr()));
}
+//===----------------------------------------------------------------------===//
+// OpenCL Expressions and Statements.
+//===----------------------------------------------------------------------===//
+void ASTStmtReader::VisitAsTypeExpr(AsTypeExpr *E) {
+ VisitExpr(E);
+ E->BuiltinLoc = ReadSourceLocation(Record, Idx);
+ E->RParenLoc = ReadSourceLocation(Record, Idx);
+ E->SrcExpr = Reader.ReadSubExpr();
+}
+
+//===----------------------------------------------------------------------===//
+// ASTReader Implementation
+//===----------------------------------------------------------------------===//
+
Stmt *ASTReader::ReadStmt(PerFileData &F) {
switch (ReadingKind) {
case Read_Decl:
@@ -1784,6 +1744,12 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) {
case EXPR_OBJC_ISA:
S = new (Context) ObjCIsaExpr(Empty);
break;
+ case EXPR_OBJC_INDIRECT_COPY_RESTORE:
+ S = new (Context) ObjCIndirectCopyRestoreExpr(Empty);
+ break;
+ case EXPR_OBJC_BRIDGED_CAST:
+ S = new (Context) ObjCBridgedCastExpr(Empty);
+ break;
case STMT_OBJC_FOR_COLLECTION:
S = new (Context) ObjCForCollectionStmt(Empty);
break;
@@ -1804,7 +1770,18 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) {
case STMT_OBJC_AT_THROW:
S = new (Context) ObjCAtThrowStmt(Empty);
break;
-
+ case STMT_OBJC_AUTORELEASE_POOL:
+ S = new (Context) ObjCAutoreleasePoolStmt(Empty);
+ break;
+ case STMT_SEH_EXCEPT:
+ S = new (Context) SEHExceptStmt(Empty);
+ break;
+ case STMT_SEH_FINALLY:
+ S = new (Context) SEHFinallyStmt(Empty);
+ break;
+ case STMT_SEH_TRY:
+ S = new (Context) SEHTryStmt(Empty);
+ break;
case STMT_CXX_CATCH:
S = new (Context) CXXCatchStmt(Empty);
break;
@@ -1978,10 +1955,18 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) {
S = new (Context) SizeOfPackExpr(Empty);
break;
+ case EXPR_SUBST_NON_TYPE_TEMPLATE_PARM:
+ S = new (Context) SubstNonTypeTemplateParmExpr(Empty);
+ break;
+
case EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK:
S = new (Context) SubstNonTypeTemplateParmPackExpr(Empty);
break;
+ case EXPR_MATERIALIZE_TEMPORARY:
+ S = new (Context) MaterializeTemporaryExpr(Empty);
+ break;
+
case EXPR_OPAQUE_VALUE: {
unsigned key = Record[ASTStmtReader::NumExprFields];
OpaqueValueExpr *&expr = OpaqueValueExprs[key];
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index ba9032e0d33e..39f2fbddf80e 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -170,6 +170,7 @@ void ASTTypeWriter::VisitFunctionType(const FunctionType *T) {
Record.push_back(C.getRegParm());
// FIXME: need to stabilize encoding of calling convention...
Record.push_back(C.getCC());
+ Record.push_back(C.getProducesResult());
}
void ASTTypeWriter::VisitFunctionNoProtoType(const FunctionNoProtoType *T) {
@@ -780,13 +781,15 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(FP_PRAGMA_OPTIONS);
RECORD(OPENCL_EXTENSIONS);
RECORD(DELEGATING_CTORS);
+ RECORD(FILE_SOURCE_LOCATION_OFFSETS);
+ RECORD(KNOWN_NAMESPACES);
// SourceManager Block.
BLOCK(SOURCE_MANAGER_BLOCK);
RECORD(SM_SLOC_FILE_ENTRY);
RECORD(SM_SLOC_BUFFER_ENTRY);
RECORD(SM_SLOC_BUFFER_BLOB);
- RECORD(SM_SLOC_INSTANTIATION_ENTRY);
+ RECORD(SM_SLOC_EXPANSION_ENTRY);
RECORD(SM_LINE_TABLE);
// Preprocessor Block.
@@ -893,7 +896,7 @@ void ASTWriter::WriteBlockInfoBlock() {
AddStmtsExprs(Stream, Record);
BLOCK(PREPROCESSOR_DETAIL_BLOCK);
- RECORD(PPD_MACRO_INSTANTIATION);
+ RECORD(PPD_MACRO_EXPANSION);
RECORD(PPD_MACRO_DEFINITION);
RECORD(PPD_INCLUSION_DIRECTIVE);
@@ -1109,6 +1112,8 @@ void ASTWriter::WriteLanguageOptions(const LangOptions &LangOpts) {
Record.push_back(LangOpts.ElideConstructors);
Record.push_back(LangOpts.SpellChecking);
Record.push_back(LangOpts.MRTD);
+ Record.push_back(LangOpts.ObjCAutoRefCount);
+ Record.push_back(LangOpts.ObjCInferRelatedReturnType);
Stream.EmitRecord(LANGUAGE_OPTIONS, Record);
}
@@ -1169,8 +1174,8 @@ void ASTWriter::WriteStatCache(MemorizeStatCalls &StatCalls) {
for (MemorizeStatCalls::iterator Stat = StatCalls.begin(),
StatEnd = StatCalls.end();
Stat != StatEnd; ++Stat, ++NumStatEntries) {
- const char *Filename = Stat->first();
- Generator.insert(Filename, Stat->second);
+ llvm::StringRef Filename = Stat->first();
+ Generator.insert(Filename.data(), Stat->second);
}
// Create the on-disk hash table in a buffer.
@@ -1245,12 +1250,12 @@ static unsigned CreateSLocBufferBlobAbbrev(llvm::BitstreamWriter &Stream) {
return Stream.EmitAbbrev(Abbrev);
}
-/// \brief Create an abbreviation for the SLocEntry that refers to an
-/// buffer.
-static unsigned CreateSLocInstantiationAbbrev(llvm::BitstreamWriter &Stream) {
+/// \brief Create an abbreviation for the SLocEntry that refers to a macro
+/// expansion.
+static unsigned CreateSLocExpansionAbbrev(llvm::BitstreamWriter &Stream) {
using namespace llvm;
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
- Abbrev->Add(BitCodeAbbrevOp(SM_SLOC_INSTANTIATION_ENTRY));
+ Abbrev->Add(BitCodeAbbrevOp(SM_SLOC_EXPANSION_ENTRY));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Spelling location
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Start location
@@ -1409,7 +1414,7 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
unsigned SLocFileAbbrv = CreateSLocFileAbbrev(Stream);
unsigned SLocBufferAbbrv = CreateSLocBufferAbbrev(Stream);
unsigned SLocBufferBlobAbbrv = CreateSLocBufferBlobAbbrev(Stream);
- unsigned SLocInstantiationAbbrv = CreateSLocInstantiationAbbrev(Stream);
+ unsigned SLocExpansionAbbrv = CreateSLocExpansionAbbrev(Stream);
// Write the line table.
if (SourceMgr.hasLineTable()) {
@@ -1474,7 +1479,7 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
} else
Code = SM_SLOC_BUFFER_ENTRY;
} else
- Code = SM_SLOC_INSTANTIATION_ENTRY;
+ Code = SM_SLOC_EXPANSION_ENTRY;
Record.clear();
Record.push_back(Code);
@@ -1534,7 +1539,7 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
PreloadSLocs.push_back(BaseSLocID + SLocEntryOffsets.size());
}
} else {
- // The source location entry is an instantiation.
+ // The source location entry is a macro expansion.
const SrcMgr::InstantiationInfo &Inst = SLoc->getInstantiation();
Record.push_back(Inst.getSpellingLoc().getRawEncoding());
Record.push_back(Inst.getInstantiationLocStart().getRawEncoding());
@@ -1545,7 +1550,7 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
if (I + 1 != N)
NextOffset = SourceMgr.getSLocEntry(I + 1).getOffset();
Record.push_back(NextOffset - SLoc->getOffset() - 1);
- Stream.EmitRecordWithAbbrev(SLocInstantiationAbbrv, Record);
+ Stream.EmitRecordWithAbbrev(SLocExpansionAbbrv, Record);
}
}
@@ -1795,13 +1800,13 @@ void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec) {
SerializationListener->SerializedPreprocessedEntity(*E,
Stream.GetCurrentBitNo());
- if (MacroInstantiation *MI = dyn_cast<MacroInstantiation>(*E)) {
+ if (MacroExpansion *ME = dyn_cast<MacroExpansion>(*E)) {
Record.push_back(IndexBase + NumPreprocessingRecords++);
- AddSourceLocation(MI->getSourceRange().getBegin(), Record);
- AddSourceLocation(MI->getSourceRange().getEnd(), Record);
- AddIdentifierRef(MI->getName(), Record);
- Record.push_back(getMacroDefinitionID(MI->getDefinition()));
- Stream.EmitRecord(PPD_MACRO_INSTANTIATION, Record);
+ AddSourceLocation(ME->getSourceRange().getBegin(), Record);
+ AddSourceLocation(ME->getSourceRange().getEnd(), Record);
+ AddIdentifierRef(ME->getName(), Record);
+ Record.push_back(getMacroDefinitionID(ME->getDefinition()));
+ Stream.EmitRecord(PPD_MACRO_EXPANSION, Record);
continue;
}
@@ -2842,6 +2847,16 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
AddDeclRef(Context.getcudaConfigureCallDecl(), CUDASpecialDeclRefs);
}
+ // Build a record containing all of the known namespaces.
+ RecordData KnownNamespaces;
+ for (llvm::DenseMap<NamespaceDecl*, bool>::iterator
+ I = SemaRef.KnownNamespaces.begin(),
+ IEnd = SemaRef.KnownNamespaces.end();
+ I != IEnd; ++I) {
+ if (!I->second)
+ AddDeclRef(I->first, KnownNamespaces);
+ }
+
// Write the remaining AST contents.
RecordData Record;
Stream.EnterSubblock(AST_BLOCK_ID, 5);
@@ -2951,6 +2966,10 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
if (!DelegatingCtorDecls.empty())
Stream.EmitRecord(DELEGATING_CTORS, DelegatingCtorDecls);
+ // Write the known namespaces.
+ if (!KnownNamespaces.empty())
+ Stream.EmitRecord(KNOWN_NAMESPACES, KnownNamespaces);
+
// Some simple statistics
Record.clear();
Record.push_back(NumStatements);
@@ -3675,6 +3694,14 @@ void ASTWriter::AddTemplateName(TemplateName Name, RecordDataImpl &Record) {
Record.push_back(DepT->getOperator());
break;
}
+
+ case TemplateName::SubstTemplateTemplateParm: {
+ SubstTemplateTemplateParmStorage *subst
+ = Name.getAsSubstTemplateTemplateParm();
+ AddDeclRef(subst->getParameter(), Record);
+ AddTemplateName(subst->getReplacement(), Record);
+ break;
+ }
case TemplateName::SubstTemplateTemplateParmPack: {
SubstTemplateTemplateParmPackStorage *SubstPack
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index 7c24088c65ba..2b8349495751 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -645,6 +645,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
Record.push_back(D->isExceptionVariable());
Record.push_back(D->isNRVOVariable());
Record.push_back(D->isCXXForRangeDecl());
+ Record.push_back(D->isARCPseudoStrong());
Record.push_back(D->getInit() ? 1 : 0);
if (D->getInit())
Writer.AddStmt(D->getInit());
@@ -670,7 +671,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
D->RedeclLink.getNext() == D &&
!D->hasCXXDirectInitializer() &&
D->getInit() == 0 &&
- !ParmVarDecl::classofKind(D->getKind()) &&
+ !isa<ParmVarDecl>(D) &&
!SpecInfo)
AbbrevToUse = Writer.getDeclVarAbbrev();
@@ -695,6 +696,8 @@ void ASTDeclWriter::VisitParmVarDecl(ParmVarDecl *D) {
Writer.AddStmt(D->getUninstantiatedDefaultArg());
Code = serialization::DECL_PARM_VAR;
+ assert(!D->isARCPseudoStrong()); // can be true of ImplicitParamDecl
+
// If the assumptions about the DECL_PARM_VAR abbrev are true, use it. Here
// we dynamically check for the properties that we optimize for, but don't
// know are true of all PARM_VAR_DECLs.
@@ -1426,6 +1429,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // isExceptionVariable
Abv->Add(BitCodeAbbrevOp(0)); // isNRVOVariable
Abv->Add(BitCodeAbbrevOp(0)); // isCXXForRangeDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // isARCPseudoStrong
Abv->Add(BitCodeAbbrevOp(0)); // HasInit
Abv->Add(BitCodeAbbrevOp(0)); // HasMemberSpecializationInfo
// ParmVarDecl
@@ -1498,6 +1502,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isExceptionVariable
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isNRVOVariable
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isCXXForRangeDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isARCPseudoStrong
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // HasInit
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // HasMemberSpecInfo
// Type Source Info
@@ -1512,8 +1517,9 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
//Stmt
//Expr
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //IsTypeDependent
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //IsValueDependent
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //TypeDependent
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //ValueDependent
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //InstantiationDependent
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //UnexpandedParamPack
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetValueKind
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetObjectKind
@@ -1531,8 +1537,9 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
//Stmt
//Expr
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //IsTypeDependent
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //IsValueDependent
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //TypeDependent
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //ValueDependent
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //InstantiationDependent
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //UnexpandedParamPack
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetValueKind
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetObjectKind
@@ -1548,8 +1555,9 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
//Stmt
//Expr
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //IsTypeDependent
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //IsValueDependent
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //TypeDependent
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //ValueDependent
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //InstantiationDependent
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //UnexpandedParamPack
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetValueKind
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetObjectKind
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index 00e240494645..1d73ed447b4f 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -39,134 +39,9 @@ namespace clang {
AddExplicitTemplateArgumentList(const ExplicitTemplateArgumentList &Args);
void VisitStmt(Stmt *S);
- void VisitNullStmt(NullStmt *S);
- void VisitCompoundStmt(CompoundStmt *S);
- void VisitSwitchCase(SwitchCase *S);
- void VisitCaseStmt(CaseStmt *S);
- void VisitDefaultStmt(DefaultStmt *S);
- void VisitLabelStmt(LabelStmt *S);
- void VisitIfStmt(IfStmt *S);
- void VisitSwitchStmt(SwitchStmt *S);
- void VisitWhileStmt(WhileStmt *S);
- void VisitDoStmt(DoStmt *S);
- void VisitForStmt(ForStmt *S);
- void VisitGotoStmt(GotoStmt *S);
- void VisitIndirectGotoStmt(IndirectGotoStmt *S);
- void VisitContinueStmt(ContinueStmt *S);
- void VisitBreakStmt(BreakStmt *S);
- void VisitReturnStmt(ReturnStmt *S);
- void VisitDeclStmt(DeclStmt *S);
- void VisitAsmStmt(AsmStmt *S);
- void VisitExpr(Expr *E);
- void VisitPredefinedExpr(PredefinedExpr *E);
- void VisitDeclRefExpr(DeclRefExpr *E);
- void VisitIntegerLiteral(IntegerLiteral *E);
- void VisitFloatingLiteral(FloatingLiteral *E);
- void VisitImaginaryLiteral(ImaginaryLiteral *E);
- void VisitStringLiteral(StringLiteral *E);
- void VisitCharacterLiteral(CharacterLiteral *E);
- void VisitParenExpr(ParenExpr *E);
- void VisitParenListExpr(ParenListExpr *E);
- void VisitUnaryOperator(UnaryOperator *E);
- void VisitOffsetOfExpr(OffsetOfExpr *E);
- void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E);
- void VisitArraySubscriptExpr(ArraySubscriptExpr *E);
- void VisitCallExpr(CallExpr *E);
- void VisitMemberExpr(MemberExpr *E);
- void VisitCastExpr(CastExpr *E);
- void VisitBinaryOperator(BinaryOperator *E);
- void VisitCompoundAssignOperator(CompoundAssignOperator *E);
- void VisitConditionalOperator(ConditionalOperator *E);
- void VisitBinaryConditionalOperator(BinaryConditionalOperator *E);
- void VisitImplicitCastExpr(ImplicitCastExpr *E);
- void VisitExplicitCastExpr(ExplicitCastExpr *E);
- void VisitCStyleCastExpr(CStyleCastExpr *E);
- void VisitCompoundLiteralExpr(CompoundLiteralExpr *E);
- void VisitExtVectorElementExpr(ExtVectorElementExpr *E);
- void VisitInitListExpr(InitListExpr *E);
- void VisitDesignatedInitExpr(DesignatedInitExpr *E);
- void VisitImplicitValueInitExpr(ImplicitValueInitExpr *E);
- void VisitVAArgExpr(VAArgExpr *E);
- void VisitAddrLabelExpr(AddrLabelExpr *E);
- void VisitStmtExpr(StmtExpr *E);
- void VisitChooseExpr(ChooseExpr *E);
- void VisitGNUNullExpr(GNUNullExpr *E);
- void VisitShuffleVectorExpr(ShuffleVectorExpr *E);
- void VisitBlockExpr(BlockExpr *E);
- void VisitBlockDeclRefExpr(BlockDeclRefExpr *E);
- void VisitGenericSelectionExpr(GenericSelectionExpr *E);
-
- // Objective-C Expressions
- void VisitObjCStringLiteral(ObjCStringLiteral *E);
- void VisitObjCEncodeExpr(ObjCEncodeExpr *E);
- void VisitObjCSelectorExpr(ObjCSelectorExpr *E);
- void VisitObjCProtocolExpr(ObjCProtocolExpr *E);
- void VisitObjCIvarRefExpr(ObjCIvarRefExpr *E);
- void VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E);
- void VisitObjCMessageExpr(ObjCMessageExpr *E);
- void VisitObjCIsaExpr(ObjCIsaExpr *E);
-
- // Objective-C Statements
- void VisitObjCForCollectionStmt(ObjCForCollectionStmt *);
- void VisitObjCAtCatchStmt(ObjCAtCatchStmt *);
- void VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *);
- void VisitObjCAtTryStmt(ObjCAtTryStmt *);
- void VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *);
- void VisitObjCAtThrowStmt(ObjCAtThrowStmt *);
-
- // C++ Statements
- void VisitCXXCatchStmt(CXXCatchStmt *S);
- void VisitCXXTryStmt(CXXTryStmt *S);
- void VisitCXXForRangeStmt(CXXForRangeStmt *);
-
- void VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E);
- void VisitCXXMemberCallExpr(CXXMemberCallExpr *E);
- void VisitCXXConstructExpr(CXXConstructExpr *E);
- void VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E);
- void VisitCXXNamedCastExpr(CXXNamedCastExpr *E);
- void VisitCXXStaticCastExpr(CXXStaticCastExpr *E);
- void VisitCXXDynamicCastExpr(CXXDynamicCastExpr *E);
- void VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *E);
- void VisitCXXConstCastExpr(CXXConstCastExpr *E);
- void VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E);
- void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E);
- void VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E);
- void VisitCXXTypeidExpr(CXXTypeidExpr *E);
- void VisitCXXUuidofExpr(CXXUuidofExpr *E);
- void VisitCXXThisExpr(CXXThisExpr *E);
- void VisitCXXThrowExpr(CXXThrowExpr *E);
- void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E);
- void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E);
-
- void VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E);
- void VisitCXXNewExpr(CXXNewExpr *E);
- void VisitCXXDeleteExpr(CXXDeleteExpr *E);
- void VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E);
-
- void VisitExprWithCleanups(ExprWithCleanups *E);
- void VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E);
- void VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E);
- void VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *E);
-
- void VisitOverloadExpr(OverloadExpr *E);
- void VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E);
- void VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E);
-
- void VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E);
- void VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E);
- void VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E);
- void VisitExpressionTraitExpr(ExpressionTraitExpr *E);
- void VisitCXXNoexceptExpr(CXXNoexceptExpr *E);
- void VisitPackExpansionExpr(PackExpansionExpr *E);
- void VisitSizeOfPackExpr(SizeOfPackExpr *E);
- void VisitSubstNonTypeTemplateParmPackExpr(
- SubstNonTypeTemplateParmPackExpr *E);
- void VisitOpaqueValueExpr(OpaqueValueExpr *E);
-
- // CUDA Expressions
- void VisitCUDAKernelCallExpr(CUDAKernelCallExpr *E);
-
- void VisitAsTypeExpr(AsTypeExpr *E);
+#define STMT(Type, Base) \
+ void Visit##Type(Type *);
+#include "clang/AST/StmtNodes.inc"
};
}
@@ -371,6 +246,7 @@ void ASTStmtWriter::VisitExpr(Expr *E) {
Writer.AddTypeRef(E->getType(), Record);
Record.push_back(E->isTypeDependent());
Record.push_back(E->isValueDependent());
+ Record.push_back(E->isInstantiationDependent());
Record.push_back(E->containsUnexpandedParameterPack());
Record.push_back(E->getValueKind());
Record.push_back(E->getObjectKind());
@@ -606,6 +482,22 @@ void ASTStmtWriter::VisitObjCIsaExpr(ObjCIsaExpr *E) {
Code = serialization::EXPR_OBJC_ISA;
}
+void ASTStmtWriter::
+VisitObjCIndirectCopyRestoreExpr(ObjCIndirectCopyRestoreExpr *E) {
+ VisitExpr(E);
+ Writer.AddStmt(E->getSubExpr());
+ Record.push_back(E->shouldCopy());
+ Code = serialization::EXPR_OBJC_INDIRECT_COPY_RESTORE;
+}
+
+void ASTStmtWriter::VisitObjCBridgedCastExpr(ObjCBridgedCastExpr *E) {
+ VisitExplicitCastExpr(E);
+ Writer.AddSourceLocation(E->getLParenLoc(), Record);
+ Writer.AddSourceLocation(E->getBridgeKeywordLoc(), Record);
+ Record.push_back(E->getBridgeKind()); // FIXME: Stable encoding
+ Code = serialization::EXPR_OBJC_BRIDGED_CAST;
+}
+
void ASTStmtWriter::VisitCastExpr(CastExpr *E) {
VisitExpr(E);
Record.push_back(E->path_size());
@@ -914,6 +806,7 @@ void ASTStmtWriter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
void ASTStmtWriter::VisitObjCMessageExpr(ObjCMessageExpr *E) {
VisitExpr(E);
Record.push_back(E->getNumArgs());
+ Record.push_back(E->isDelegateInitCall());
Record.push_back((unsigned)E->getReceiverKind()); // FIXME: stable encoding
switch (E->getReceiverKind()) {
case ObjCMessageExpr::Instance:
@@ -973,6 +866,12 @@ void ASTStmtWriter::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *S) {
Code = serialization::STMT_OBJC_FINALLY;
}
+void ASTStmtWriter::VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S) {
+ Writer.AddStmt(S->getSubStmt());
+ Writer.AddSourceLocation(S->getAtLoc(), Record);
+ Code = serialization::STMT_OBJC_AUTORELEASE_POOL;
+}
+
void ASTStmtWriter::VisitObjCAtTryStmt(ObjCAtTryStmt *S) {
Record.push_back(S->getNumCatchStmts());
Record.push_back(S->getFinallyStmt() != 0);
@@ -1123,18 +1022,6 @@ void ASTStmtWriter::VisitCXXTypeidExpr(CXXTypeidExpr *E) {
}
}
-void ASTStmtWriter::VisitCXXUuidofExpr(CXXUuidofExpr *E) {
- VisitExpr(E);
- Writer.AddSourceRange(E->getSourceRange(), Record);
- if (E->isTypeOperand()) {
- Writer.AddTypeSourceInfo(E->getTypeOperandSourceInfo(), Record);
- Code = serialization::EXPR_CXX_UUIDOF_TYPE;
- } else {
- Writer.AddStmt(E->getExprOperand());
- Code = serialization::EXPR_CXX_UUIDOF_EXPR;
- }
-}
-
void ASTStmtWriter::VisitCXXThisExpr(CXXThisExpr *E) {
VisitExpr(E);
Writer.AddSourceLocation(E->getLocation(), Record);
@@ -1146,6 +1033,7 @@ void ASTStmtWriter::VisitCXXThrowExpr(CXXThrowExpr *E) {
VisitExpr(E);
Writer.AddSourceLocation(E->getThrowLoc(), Record);
Writer.AddStmt(E->getSubExpr());
+ Record.push_back(E->isThrownVariableInScope());
Code = serialization::EXPR_CXX_THROW;
}
@@ -1408,15 +1296,30 @@ void ASTStmtWriter::VisitSizeOfPackExpr(SizeOfPackExpr *E) {
Code = serialization::EXPR_SIZEOF_PACK;
}
+void ASTStmtWriter::VisitSubstNonTypeTemplateParmExpr(
+ SubstNonTypeTemplateParmExpr *E) {
+ VisitExpr(E);
+ Writer.AddDeclRef(E->getParameter(), Record);
+ Writer.AddSourceLocation(E->getNameLoc(), Record);
+ Writer.AddStmt(E->getReplacement());
+ Code = serialization::EXPR_SUBST_NON_TYPE_TEMPLATE_PARM;
+}
+
void ASTStmtWriter::VisitSubstNonTypeTemplateParmPackExpr(
SubstNonTypeTemplateParmPackExpr *E) {
VisitExpr(E);
- Writer.AddDeclRef(E->Param, Record);
+ Writer.AddDeclRef(E->getParameterPack(), Record);
Writer.AddTemplateArgument(E->getArgumentPack(), Record);
- Writer.AddSourceLocation(E->NameLoc, Record);
+ Writer.AddSourceLocation(E->getParameterPackLocation(), Record);
Code = serialization::EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK;
}
+void ASTStmtWriter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) {
+ VisitExpr(E);
+ Writer.AddStmt(E->Temporary);
+ Code = serialization::EXPR_MATERIALIZE_TEMPORARY;
+}
+
void ASTStmtWriter::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
VisitExpr(E);
Record.push_back(Writer.getOpaqueValueID(E));
@@ -1439,11 +1342,52 @@ void ASTStmtWriter::VisitCUDAKernelCallExpr(CUDAKernelCallExpr *E) {
//===----------------------------------------------------------------------===//
void ASTStmtWriter::VisitAsTypeExpr(AsTypeExpr *E) {
VisitExpr(E);
+ Writer.AddSourceLocation(E->getBuiltinLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
Writer.AddStmt(E->getSrcExpr());
Code = serialization::EXPR_ASTYPE;
}
//===----------------------------------------------------------------------===//
+// Microsoft Expressions and Statements.
+//===----------------------------------------------------------------------===//
+void ASTStmtWriter::VisitCXXUuidofExpr(CXXUuidofExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceRange(E->getSourceRange(), Record);
+ if (E->isTypeOperand()) {
+ Writer.AddTypeSourceInfo(E->getTypeOperandSourceInfo(), Record);
+ Code = serialization::EXPR_CXX_UUIDOF_TYPE;
+ } else {
+ Writer.AddStmt(E->getExprOperand());
+ Code = serialization::EXPR_CXX_UUIDOF_EXPR;
+ }
+}
+
+void ASTStmtWriter::VisitSEHExceptStmt(SEHExceptStmt *S) {
+ VisitStmt(S);
+ Writer.AddSourceLocation(S->getExceptLoc(), Record);
+ Writer.AddStmt(S->getFilterExpr());
+ Writer.AddStmt(S->getBlock());
+ Code = serialization::STMT_SEH_EXCEPT;
+}
+
+void ASTStmtWriter::VisitSEHFinallyStmt(SEHFinallyStmt *S) {
+ VisitStmt(S);
+ Writer.AddSourceLocation(S->getFinallyLoc(), Record);
+ Writer.AddStmt(S->getBlock());
+ Code = serialization::STMT_SEH_FINALLY;
+}
+
+void ASTStmtWriter::VisitSEHTryStmt(SEHTryStmt *S) {
+ VisitStmt(S);
+ Record.push_back(S->getIsCXXTry());
+ Writer.AddSourceLocation(S->getTryLoc(), Record);
+ Writer.AddStmt(S->getTryBlock());
+ Writer.AddStmt(S->getHandler());
+ Code = serialization::STMT_SEH_TRY;
+}
+
+//===----------------------------------------------------------------------===//
// ASTWriter Implementation
//===----------------------------------------------------------------------===//
diff --git a/lib/Serialization/ChainedIncludesSource.cpp b/lib/Serialization/ChainedIncludesSource.cpp
index da5be957a530..3b7cd23b92ae 100644
--- a/lib/Serialization/ChainedIncludesSource.cpp
+++ b/lib/Serialization/ChainedIncludesSource.cpp
@@ -185,7 +185,8 @@ ChainedIncludesSource::FindExternalVisibleDeclsByName(const DeclContext *DC,
void ChainedIncludesSource::MaterializeVisibleDecls(const DeclContext *DC) {
return getFinalReader().MaterializeVisibleDecls(DC);
}
-bool ChainedIncludesSource::FindExternalLexicalDecls(const DeclContext *DC,
+ExternalLoadResult
+ChainedIncludesSource::FindExternalLexicalDecls(const DeclContext *DC,
bool (*isKindWeWant)(Decl::Kind),
llvm::SmallVectorImpl<Decl*> &Result) {
return getFinalReader().FindExternalLexicalDecls(DC, isKindWeWant, Result);
diff --git a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
index 235b400eb9e3..9fc8163ab8b9 100644
--- a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
+++ b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
@@ -606,7 +606,7 @@ void VariadicMethodTypeChecker::checkPreObjCMessage(ObjCMessage msg,
continue;
// Ignore CF references, which can be toll-free bridged.
- if (cocoa::isCFObjectRef(ArgTy))
+ if (coreFoundation::isCFObjectRef(ArgTy))
continue;
// Generate only one error node to use for all bug reports.
diff --git a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index f2f5c1ed44e9..c5dac5d21626 100644
--- a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -30,8 +30,11 @@ class CStringChecker : public Checker< eval::Call,
check::DeadSymbols,
check::RegionChanges
> {
- mutable llvm::OwningPtr<BugType> BT_Null, BT_Bounds, BT_BoundsWrite,
- BT_Overlap, BT_NotCString;
+ mutable llvm::OwningPtr<BugType> BT_Null, BT_Bounds,
+ BT_Overlap, BT_NotCString,
+ BT_AdditionOverflow;
+ mutable const char *CurrentFunctionDescription;
+
public:
static void *getTag() { static int tag; return &tag; }
@@ -91,9 +94,11 @@ public:
const MemRegion *MR, SVal strLength);
static SVal getCStringLengthForRegion(CheckerContext &C,
const GRState *&state,
- const Expr *Ex, const MemRegion *MR);
+ const Expr *Ex, const MemRegion *MR,
+ bool hypothetical);
SVal getCStringLength(CheckerContext &C, const GRState *&state,
- const Expr *Ex, SVal Buf) const;
+ const Expr *Ex, SVal Buf,
+ bool hypothetical = false) const;
const StringLiteral *getCStringLiteral(CheckerContext &C,
const GRState *&state,
@@ -112,17 +117,29 @@ public:
const Expr *S, SVal l) const;
const GRState *CheckLocation(CheckerContext &C, const GRState *state,
const Expr *S, SVal l,
- bool IsDestination = false) const;
+ const char *message = NULL) const;
const GRState *CheckBufferAccess(CheckerContext &C, const GRState *state,
const Expr *Size,
const Expr *FirstBuf,
- const Expr *SecondBuf = NULL,
- bool FirstIsDestination = false) const;
+ const Expr *SecondBuf,
+ const char *firstMessage = NULL,
+ const char *secondMessage = NULL,
+ bool WarnAboutSize = false) const;
+ const GRState *CheckBufferAccess(CheckerContext &C, const GRState *state,
+ const Expr *Size, const Expr *Buf,
+ const char *message = NULL,
+ bool WarnAboutSize = false) const {
+ // This is a convenience override.
+ return CheckBufferAccess(C, state, Size, Buf, NULL, message, NULL,
+ WarnAboutSize);
+ }
const GRState *CheckOverlap(CheckerContext &C, const GRState *state,
const Expr *Size, const Expr *First,
const Expr *Second) const;
void emitOverlapBug(CheckerContext &C, const GRState *state,
const Stmt *First, const Stmt *Second) const;
+ const GRState *checkAdditionOverflow(CheckerContext &C, const GRState *state,
+ NonLoc left, NonLoc right) const;
};
class CStringLength {
@@ -176,10 +193,14 @@ const GRState *CStringChecker::checkNonNull(CheckerContext &C,
BT_Null.reset(new BuiltinBug("API",
"Null pointer argument in call to byte string function"));
+ llvm::SmallString<80> buf;
+ llvm::raw_svector_ostream os(buf);
+ assert(CurrentFunctionDescription);
+ os << "Null pointer argument in call to " << CurrentFunctionDescription;
+
// Generate a report for this bug.
BuiltinBug *BT = static_cast<BuiltinBug*>(BT_Null.get());
- EnhancedBugReport *report = new EnhancedBugReport(*BT,
- BT->getDescription(), N);
+ EnhancedBugReport *report = new EnhancedBugReport(*BT, os.str(), N);
report->addRange(S->getSourceRange());
report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, S);
@@ -196,7 +217,7 @@ const GRState *CStringChecker::checkNonNull(CheckerContext &C,
const GRState *CStringChecker::CheckLocation(CheckerContext &C,
const GRState *state,
const Expr *S, SVal l,
- bool IsDestination) const {
+ const char *warningMsg) const {
// If a previous check has failed, propagate the failure.
if (!state)
return NULL;
@@ -216,7 +237,8 @@ const GRState *CStringChecker::CheckLocation(CheckerContext &C,
// Get the size of the array.
const SubRegion *superReg = cast<SubRegion>(ER->getSuperRegion());
SValBuilder &svalBuilder = C.getSValBuilder();
- SVal Extent = svalBuilder.convertToArrayIndex(superReg->getExtent(svalBuilder));
+ SVal Extent =
+ svalBuilder.convertToArrayIndex(superReg->getExtent(svalBuilder));
DefinedOrUnknownSVal Size = cast<DefinedOrUnknownSVal>(Extent);
// Get the index of the accessed element.
@@ -229,28 +251,32 @@ const GRState *CStringChecker::CheckLocation(CheckerContext &C,
if (!N)
return NULL;
- BuiltinBug *BT;
- if (IsDestination) {
- if (!BT_BoundsWrite) {
- BT_BoundsWrite.reset(new BuiltinBug("Out-of-bound array access",
- "Byte string function overflows destination buffer"));
- }
- BT = static_cast<BuiltinBug*>(BT_BoundsWrite.get());
+ if (!BT_Bounds) {
+ BT_Bounds.reset(new BuiltinBug("Out-of-bound array access",
+ "Byte string function accesses out-of-bound array element"));
+ }
+ BuiltinBug *BT = static_cast<BuiltinBug*>(BT_Bounds.get());
+
+ // Generate a report for this bug.
+ RangedBugReport *report;
+ if (warningMsg) {
+ report = new RangedBugReport(*BT, warningMsg, N);
} else {
- if (!BT_Bounds) {
- BT_Bounds.reset(new BuiltinBug("Out-of-bound array access",
- "Byte string function accesses out-of-bound array element"));
- }
- BT = static_cast<BuiltinBug*>(BT_Bounds.get());
+ assert(CurrentFunctionDescription);
+ assert(CurrentFunctionDescription[0] != '\0');
+
+ llvm::SmallString<80> buf;
+ llvm::raw_svector_ostream os(buf);
+ os << (char)toupper(CurrentFunctionDescription[0])
+ << &CurrentFunctionDescription[1]
+ << " accesses out-of-bound array element";
+ report = new RangedBugReport(*BT, os.str(), N);
}
// FIXME: It would be nice to eventually make this diagnostic more clear,
// e.g., by referencing the original declaration or by saying *why* this
// reference is outside the range.
- // Generate a report for this bug.
- RangedBugReport *report = new RangedBugReport(*BT, BT->getDescription(), N);
-
report->addRange(S->getSourceRange());
C.EmitReport(report);
return NULL;
@@ -266,13 +292,15 @@ const GRState *CStringChecker::CheckBufferAccess(CheckerContext &C,
const Expr *Size,
const Expr *FirstBuf,
const Expr *SecondBuf,
- bool FirstIsDestination) const {
+ const char *firstMessage,
+ const char *secondMessage,
+ bool WarnAboutSize) const {
// If a previous check has failed, propagate the failure.
if (!state)
return NULL;
SValBuilder &svalBuilder = C.getSValBuilder();
- ASTContext &Ctx = C.getASTContext();
+ ASTContext &Ctx = svalBuilder.getContext();
QualType sizeTy = Size->getType();
QualType PtrTy = Ctx.getPointerType(Ctx.CharTy);
@@ -284,6 +312,8 @@ const GRState *CStringChecker::CheckBufferAccess(CheckerContext &C,
return NULL;
// Get the access length and make sure it is known.
+ // FIXME: This assumes the caller has already checked that the access length
+ // is positive. And that it's unsigned.
SVal LengthVal = state->getSVal(Size);
NonLoc *Length = dyn_cast<NonLoc>(&LengthVal);
if (!Length)
@@ -297,9 +327,11 @@ const GRState *CStringChecker::CheckBufferAccess(CheckerContext &C,
// Check that the first buffer is sufficiently long.
SVal BufStart = svalBuilder.evalCast(BufVal, PtrTy, FirstBuf->getType());
if (Loc *BufLoc = dyn_cast<Loc>(&BufStart)) {
+ const Expr *warningExpr = (WarnAboutSize ? Size : FirstBuf);
+
SVal BufEnd = svalBuilder.evalBinOpLN(state, BO_Add, *BufLoc,
LastOffset, PtrTy);
- state = CheckLocation(C, state, FirstBuf, BufEnd, FirstIsDestination);
+ state = CheckLocation(C, state, warningExpr, BufEnd, firstMessage);
// If the buffer isn't large enough, abort.
if (!state)
@@ -315,9 +347,11 @@ const GRState *CStringChecker::CheckBufferAccess(CheckerContext &C,
BufStart = svalBuilder.evalCast(BufVal, PtrTy, SecondBuf->getType());
if (Loc *BufLoc = dyn_cast<Loc>(&BufStart)) {
+ const Expr *warningExpr = (WarnAboutSize ? Size : SecondBuf);
+
SVal BufEnd = svalBuilder.evalBinOpLN(state, BO_Add, *BufLoc,
LastOffset, PtrTy);
- state = CheckLocation(C, state, SecondBuf, BufEnd);
+ state = CheckLocation(C, state, warningExpr, BufEnd, secondMessage);
}
}
@@ -368,8 +402,7 @@ const GRState *CStringChecker::CheckOverlap(CheckerContext &C,
state = stateFalse;
// Which value comes first?
- ASTContext &Ctx = svalBuilder.getContext();
- QualType cmpTy = Ctx.IntTy;
+ QualType cmpTy = svalBuilder.getConditionType();
SVal reverse = svalBuilder.evalBinOpLL(state, BO_GT,
*firstLoc, *secondLoc, cmpTy);
DefinedOrUnknownSVal *reverseTest = dyn_cast<DefinedOrUnknownSVal>(&reverse);
@@ -402,8 +435,10 @@ const GRState *CStringChecker::CheckOverlap(CheckerContext &C,
// Convert the first buffer's start address to char*.
// Bail out if the cast fails.
+ ASTContext &Ctx = svalBuilder.getContext();
QualType CharPtrTy = Ctx.getPointerType(Ctx.CharTy);
- SVal FirstStart = svalBuilder.evalCast(*firstLoc, CharPtrTy, First->getType());
+ SVal FirstStart = svalBuilder.evalCast(*firstLoc, CharPtrTy,
+ First->getType());
Loc *FirstStartLoc = dyn_cast<Loc>(&FirstStart);
if (!FirstStartLoc)
return state;
@@ -454,12 +489,78 @@ void CStringChecker::emitOverlapBug(CheckerContext &C, const GRState *state,
C.EmitReport(report);
}
+const GRState *CStringChecker::checkAdditionOverflow(CheckerContext &C,
+ const GRState *state,
+ NonLoc left,
+ NonLoc right) const {
+ // If a previous check has failed, propagate the failure.
+ if (!state)
+ return NULL;
+
+ SValBuilder &svalBuilder = C.getSValBuilder();
+ BasicValueFactory &BVF = svalBuilder.getBasicValueFactory();
+
+ QualType sizeTy = svalBuilder.getContext().getSizeType();
+ const llvm::APSInt &maxValInt = BVF.getMaxValue(sizeTy);
+ NonLoc maxVal = svalBuilder.makeIntVal(maxValInt);
+
+ SVal maxMinusRight = svalBuilder.evalBinOpNN(state, BO_Sub, maxVal, right,
+ sizeTy);
+
+ if (maxMinusRight.isUnknownOrUndef()) {
+ // Try switching the operands. (The order of these two assignments is
+ // important!)
+ maxMinusRight = svalBuilder.evalBinOpNN(state, BO_Sub, maxVal, left,
+ sizeTy);
+ left = right;
+ }
+
+ if (NonLoc *maxMinusRightNL = dyn_cast<NonLoc>(&maxMinusRight)) {
+ QualType cmpTy = svalBuilder.getConditionType();
+ // If left > max - right, we have an overflow.
+ SVal willOverflow = svalBuilder.evalBinOpNN(state, BO_GT, left,
+ *maxMinusRightNL, cmpTy);
+
+ const GRState *stateOverflow, *stateOkay;
+ llvm::tie(stateOverflow, stateOkay) =
+ state->assume(cast<DefinedOrUnknownSVal>(willOverflow));
+
+ if (stateOverflow && !stateOkay) {
+ // We have an overflow. Emit a bug report.
+ ExplodedNode *N = C.generateSink(stateOverflow);
+ if (!N)
+ return NULL;
+
+ if (!BT_AdditionOverflow)
+ BT_AdditionOverflow.reset(new BuiltinBug("API",
+ "Sum of expressions causes overflow"));
+
+ // This isn't a great error message, but this should never occur in real
+ // code anyway -- you'd have to create a buffer longer than a size_t can
+ // represent, which is sort of a contradiction.
+ const char *warning =
+ "This expression will create a string whose length is too big to "
+ "be represented as a size_t";
+
+ // Generate a report for this bug.
+ BugReport *report = new BugReport(*BT_AdditionOverflow, warning, N);
+ C.EmitReport(report);
+
+ return NULL;
+ }
+
+ // From now on, assume an overflow didn't occur.
+ assert(stateOkay);
+ state = stateOkay;
+ }
+
+ return state;
+}
+
const GRState *CStringChecker::setCStringLength(const GRState *state,
const MemRegion *MR,
SVal strLength) {
assert(!strLength.isUndef() && "Attempt to set an undefined string length");
- if (strLength.isUnknown())
- return state;
MR = MR->StripCasts();
@@ -474,7 +575,8 @@ const GRState *CStringChecker::setCStringLength(const GRState *state,
case MemRegion::VarRegionKind:
case MemRegion::FieldRegionKind:
case MemRegion::ObjCIvarRegionKind:
- return state->set<CStringLength>(MR, strLength);
+ // These are the types we can currently track string lengths for.
+ break;
case MemRegion::ElementRegionKind:
// FIXME: Handle element regions by upper-bounding the parent region's
@@ -488,16 +590,24 @@ const GRState *CStringChecker::setCStringLength(const GRState *state,
// warning for things like strcpy((char[]){'a', 0}, "b");
return state;
}
+
+ if (strLength.isUnknown())
+ return state->remove<CStringLength>(MR);
+
+ return state->set<CStringLength>(MR, strLength);
}
SVal CStringChecker::getCStringLengthForRegion(CheckerContext &C,
const GRState *&state,
const Expr *Ex,
- const MemRegion *MR) {
- // If there's a recorded length, go ahead and return it.
- const SVal *Recorded = state->get<CStringLength>(MR);
- if (Recorded)
- return *Recorded;
+ const MemRegion *MR,
+ bool hypothetical) {
+ if (!hypothetical) {
+ // If there's a recorded length, go ahead and return it.
+ const SVal *Recorded = state->get<CStringLength>(MR);
+ if (Recorded)
+ return *Recorded;
+ }
// Otherwise, get a new symbol and update the state.
unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
@@ -505,12 +615,16 @@ SVal CStringChecker::getCStringLengthForRegion(CheckerContext &C,
QualType sizeTy = svalBuilder.getContext().getSizeType();
SVal strLength = svalBuilder.getMetadataSymbolVal(CStringChecker::getTag(),
MR, Ex, sizeTy, Count);
- state = state->set<CStringLength>(MR, strLength);
+
+ if (!hypothetical)
+ state = state->set<CStringLength>(MR, strLength);
+
return strLength;
}
SVal CStringChecker::getCStringLength(CheckerContext &C, const GRState *&state,
- const Expr *Ex, SVal Buf) const {
+ const Expr *Ex, SVal Buf,
+ bool hypothetical) const {
const MemRegion *MR = Buf.getAsRegion();
if (!MR) {
// If we can't get a region, see if it's something we /know/ isn't a
@@ -524,8 +638,9 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, const GRState *&state,
llvm::SmallString<120> buf;
llvm::raw_svector_ostream os(buf);
- os << "Argument to byte string function is the address of the label '"
- << Label->getLabel()->getName()
+ assert(CurrentFunctionDescription);
+ os << "Argument to " << CurrentFunctionDescription
+ << " is the address of the label '" << Label->getLabel()->getName()
<< "', which is not a null-terminated string";
// Generate a report for this bug.
@@ -561,7 +676,7 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, const GRState *&state,
case MemRegion::VarRegionKind:
case MemRegion::FieldRegionKind:
case MemRegion::ObjCIvarRegionKind:
- return getCStringLengthForRegion(C, state, Ex, MR);
+ return getCStringLengthForRegion(C, state, Ex, MR, hypothetical);
case MemRegion::CompoundLiteralRegionKind:
// FIXME: Can we track this? Is it necessary?
return UnknownVal();
@@ -581,7 +696,8 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, const GRState *&state,
llvm::SmallString<120> buf;
llvm::raw_svector_ostream os(buf);
- os << "Argument to byte string function is ";
+ assert(CurrentFunctionDescription);
+ os << "Argument to " << CurrentFunctionDescription << " is ";
if (SummarizeRegion(os, C.getASTContext(), MR))
os << ", which is not a null-terminated string";
@@ -700,12 +816,15 @@ void CStringChecker::evalCopyCommon(CheckerContext &C,
const Expr *Size, const Expr *Dest,
const Expr *Source, bool Restricted,
bool IsMempcpy) const {
+ CurrentFunctionDescription = "memory copy function";
+
// See if the size argument is zero.
SVal sizeVal = state->getSVal(Size);
QualType sizeTy = Size->getType();
const GRState *stateZeroSize, *stateNonZeroSize;
- llvm::tie(stateZeroSize, stateNonZeroSize) = assumeZero(C, state, sizeVal, sizeTy);
+ llvm::tie(stateZeroSize, stateNonZeroSize) =
+ assumeZero(C, state, sizeVal, sizeTy);
// Get the value of the Dest.
SVal destVal = state->getSVal(Dest);
@@ -737,8 +856,10 @@ void CStringChecker::evalCopyCommon(CheckerContext &C,
return;
// Ensure the accesses are valid and that the buffers do not overlap.
+ const char * const writeWarning =
+ "Memory copy function overflows destination buffer";
state = CheckBufferAccess(C, state, Size, Dest, Source,
- /* FirstIsDst = */ true);
+ writeWarning, /* sourceWarning = */ NULL);
if (Restricted)
state = CheckOverlap(C, state, Size, Dest, Source);
@@ -824,6 +945,8 @@ void CStringChecker::evalBcopy(CheckerContext &C, const CallExpr *CE) const {
void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const {
// int memcmp(const void *s1, const void *s2, size_t n);
+ CurrentFunctionDescription = "memory comparison function";
+
const Expr *Left = CE->getArg(0);
const Expr *Right = CE->getArg(1);
const Expr *Size = CE->getArg(2);
@@ -861,7 +984,7 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const {
const GRState *StSameBuf, *StNotSameBuf;
llvm::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf);
- // If the two arguments might be the same buffer, we know the result is zero,
+ // If the two arguments might be the same buffer, we know the result is 0,
// and we only need to check one size.
if (StSameBuf) {
state = StSameBuf;
@@ -902,58 +1025,126 @@ void CStringChecker::evalstrnLength(CheckerContext &C,
void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
bool IsStrnlen) const {
+ CurrentFunctionDescription = "string length function";
const GRState *state = C.getState();
+
+ if (IsStrnlen) {
+ const Expr *maxlenExpr = CE->getArg(1);
+ SVal maxlenVal = state->getSVal(maxlenExpr);
+
+ const GRState *stateZeroSize, *stateNonZeroSize;
+ llvm::tie(stateZeroSize, stateNonZeroSize) =
+ assumeZero(C, state, maxlenVal, maxlenExpr->getType());
+
+ // If the size can be zero, the result will be 0 in that case, and we don't
+ // have to check the string itself.
+ if (stateZeroSize) {
+ SVal zero = C.getSValBuilder().makeZeroVal(CE->getType());
+ stateZeroSize = stateZeroSize->BindExpr(CE, zero);
+ C.addTransition(stateZeroSize);
+ }
+
+ // If the size is GUARANTEED to be zero, we're done!
+ if (!stateNonZeroSize)
+ return;
+
+ // Otherwise, record the assumption that the size is nonzero.
+ state = stateNonZeroSize;
+ }
+
+ // Check that the string argument is non-null.
const Expr *Arg = CE->getArg(0);
SVal ArgVal = state->getSVal(Arg);
- // Check that the argument is non-null.
state = checkNonNull(C, state, Arg, ArgVal);
- if (state) {
- SVal strLength = getCStringLength(C, state, Arg, ArgVal);
+ if (!state)
+ return;
- // If the argument isn't a valid C string, there's no valid state to
- // transition to.
- if (strLength.isUndef())
- return;
+ SVal strLength = getCStringLength(C, state, Arg, ArgVal);
- // If the check is for strnlen() then bind the return value to no more than
- // the maxlen value.
- if (IsStrnlen) {
- const Expr *maxlenExpr = CE->getArg(1);
- SVal maxlenVal = state->getSVal(maxlenExpr);
-
- NonLoc *strLengthNL = dyn_cast<NonLoc>(&strLength);
- NonLoc *maxlenValNL = dyn_cast<NonLoc>(&maxlenVal);
+ // If the argument isn't a valid C string, there's no valid state to
+ // transition to.
+ if (strLength.isUndef())
+ return;
- QualType cmpTy = C.getSValBuilder().getContext().IntTy;
- const GRState *stateTrue, *stateFalse;
-
- // Check if the strLength is greater than or equal to the maxlen
- llvm::tie(stateTrue, stateFalse) =
+ DefinedOrUnknownSVal result = UnknownVal();
+
+ // If the check is for strnlen() then bind the return value to no more than
+ // the maxlen value.
+ if (IsStrnlen) {
+ QualType cmpTy = C.getSValBuilder().getConditionType();
+
+ // It's a little unfortunate to be getting this again,
+ // but it's not that expensive...
+ const Expr *maxlenExpr = CE->getArg(1);
+ SVal maxlenVal = state->getSVal(maxlenExpr);
+
+ NonLoc *strLengthNL = dyn_cast<NonLoc>(&strLength);
+ NonLoc *maxlenValNL = dyn_cast<NonLoc>(&maxlenVal);
+
+ if (strLengthNL && maxlenValNL) {
+ const GRState *stateStringTooLong, *stateStringNotTooLong;
+
+ // Check if the strLength is greater than the maxlen.
+ llvm::tie(stateStringTooLong, stateStringNotTooLong) =
state->assume(cast<DefinedOrUnknownSVal>
- (C.getSValBuilder().evalBinOpNN(state, BO_GE,
- *strLengthNL, *maxlenValNL,
+ (C.getSValBuilder().evalBinOpNN(state, BO_GT,
+ *strLengthNL,
+ *maxlenValNL,
cmpTy)));
- // If the strLength is greater than or equal to the maxlen, set strLength
- // to maxlen
- if (stateTrue && !stateFalse) {
- strLength = maxlenVal;
+ if (stateStringTooLong && !stateStringNotTooLong) {
+ // If the string is longer than maxlen, return maxlen.
+ result = *maxlenValNL;
+ } else if (stateStringNotTooLong && !stateStringTooLong) {
+ // If the string is shorter than maxlen, return its length.
+ result = *strLengthNL;
}
}
- // If getCStringLength couldn't figure out the length, conjure a return
- // value, so it can be used in constraints, at least.
- if (strLength.isUnknown()) {
+ if (result.isUnknown()) {
+ // If we don't have enough information for a comparison, there's
+ // no guarantee the full string length will actually be returned.
+ // All we know is the return value is the min of the string length
+ // and the limit. This is better than nothing.
unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
- strLength = C.getSValBuilder().getConjuredSymbolVal(NULL, CE, Count);
+ result = C.getSValBuilder().getConjuredSymbolVal(NULL, CE, Count);
+ NonLoc *resultNL = cast<NonLoc>(&result);
+
+ if (strLengthNL) {
+ state = state->assume(cast<DefinedOrUnknownSVal>
+ (C.getSValBuilder().evalBinOpNN(state, BO_LE,
+ *resultNL,
+ *strLengthNL,
+ cmpTy)), true);
+ }
+
+ if (maxlenValNL) {
+ state = state->assume(cast<DefinedOrUnknownSVal>
+ (C.getSValBuilder().evalBinOpNN(state, BO_LE,
+ *resultNL,
+ *maxlenValNL,
+ cmpTy)), true);
+ }
}
- // Bind the return value.
- state = state->BindExpr(CE, strLength);
- C.addTransition(state);
+ } else {
+ // This is a plain strlen(), not strnlen().
+ result = cast<DefinedOrUnknownSVal>(strLength);
+
+ // If we don't know the length of the string, conjure a return
+ // value, so it can be used in constraints, at least.
+ if (result.isUnknown()) {
+ unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
+ result = C.getSValBuilder().getConjuredSymbolVal(NULL, CE, Count);
+ }
}
+
+ // Bind the return value.
+ assert(!result.isUnknown() && "Should have conjured a value by now");
+ state = state->BindExpr(CE, result);
+ C.addTransition(state);
}
void CStringChecker::evalStrcpy(CheckerContext &C, const CallExpr *CE) const {
@@ -999,6 +1190,7 @@ void CStringChecker::evalStrncat(CheckerContext &C, const CallExpr *CE) const {
void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
bool returnEnd, bool isBounded,
bool isAppending) const {
+ CurrentFunctionDescription = "string copy function";
const GRState *state = C.getState();
// Check that the destination is non-null.
@@ -1023,76 +1215,240 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
if (strLength.isUndef())
return;
+ SValBuilder &svalBuilder = C.getSValBuilder();
+ QualType cmpTy = svalBuilder.getConditionType();
+ QualType sizeTy = svalBuilder.getContext().getSizeType();
+
+ // These two values allow checking two kinds of errors:
+ // - actual overflows caused by a source that doesn't fit in the destination
+ // - potential overflows caused by a bound that could exceed the destination
+ SVal amountCopied = UnknownVal();
+ SVal maxLastElementIndex = UnknownVal();
+ const char *boundWarning = NULL;
+
// If the function is strncpy, strncat, etc... it is bounded.
if (isBounded) {
// Get the max number of characters to copy.
const Expr *lenExpr = CE->getArg(2);
SVal lenVal = state->getSVal(lenExpr);
- // Cast the length to a NonLoc SVal. If it is not a NonLoc then give up.
- NonLoc *strLengthNL = dyn_cast<NonLoc>(&strLength);
- if (!strLengthNL)
- return;
+ // Protect against misdeclared strncpy().
+ lenVal = svalBuilder.evalCast(lenVal, sizeTy, lenExpr->getType());
- // Cast the max length to a NonLoc SVal. If it is not a NonLoc then give up.
+ NonLoc *strLengthNL = dyn_cast<NonLoc>(&strLength);
NonLoc *lenValNL = dyn_cast<NonLoc>(&lenVal);
- if (!lenValNL)
- return;
- QualType cmpTy = C.getSValBuilder().getContext().IntTy;
- const GRState *stateTrue, *stateFalse;
-
- // Check if the max number to copy is less than the length of the src.
- llvm::tie(stateTrue, stateFalse) =
- state->assume(cast<DefinedOrUnknownSVal>
- (C.getSValBuilder().evalBinOpNN(state, BO_GT,
- *strLengthNL, *lenValNL,
- cmpTy)));
-
- if (stateTrue) {
- // Max number to copy is less than the length of the src, so the actual
- // strLength copied is the max number arg.
- strLength = lenVal;
- }
+ // If we know both values, we might be able to figure out how much
+ // we're copying.
+ if (strLengthNL && lenValNL) {
+ const GRState *stateSourceTooLong, *stateSourceNotTooLong;
+
+ // Check if the max number to copy is less than the length of the src.
+ // If the bound is equal to the source length, strncpy won't null-
+ // terminate the result!
+ llvm::tie(stateSourceTooLong, stateSourceNotTooLong) =
+ state->assume(cast<DefinedOrUnknownSVal>
+ (svalBuilder.evalBinOpNN(state, BO_GE, *strLengthNL,
+ *lenValNL, cmpTy)));
+
+ if (stateSourceTooLong && !stateSourceNotTooLong) {
+ // Max number to copy is less than the length of the src, so the actual
+ // strLength copied is the max number arg.
+ state = stateSourceTooLong;
+ amountCopied = lenVal;
+
+ } else if (!stateSourceTooLong && stateSourceNotTooLong) {
+ // The source buffer entirely fits in the bound.
+ state = stateSourceNotTooLong;
+ amountCopied = strLength;
+ }
+ }
+
+ // We still want to know if the bound is known to be too large.
+ if (lenValNL) {
+ if (isAppending) {
+ // For strncat, the check is strlen(dst) + lenVal < sizeof(dst)
+
+ // Get the string length of the destination. If the destination is
+ // memory that can't have a string length, we shouldn't be copying
+ // into it anyway.
+ SVal dstStrLength = getCStringLength(C, state, Dst, DstVal);
+ if (dstStrLength.isUndef())
+ return;
+
+ if (NonLoc *dstStrLengthNL = dyn_cast<NonLoc>(&dstStrLength)) {
+ maxLastElementIndex = svalBuilder.evalBinOpNN(state, BO_Add,
+ *lenValNL,
+ *dstStrLengthNL,
+ sizeTy);
+ boundWarning = "Size argument is greater than the free space in the "
+ "destination buffer";
+ }
+
+ } else {
+ // For strncpy, this is just checking that lenVal <= sizeof(dst)
+ // (Yes, strncpy and strncat differ in how they treat termination.
+ // strncat ALWAYS terminates, but strncpy doesn't.)
+ NonLoc one = cast<NonLoc>(svalBuilder.makeIntVal(1, sizeTy));
+ maxLastElementIndex = svalBuilder.evalBinOpNN(state, BO_Sub, *lenValNL,
+ one, sizeTy);
+ boundWarning = "Size argument is greater than the length of the "
+ "destination buffer";
+ }
+ }
+
+ // If we couldn't pin down the copy length, at least bound it.
+ // FIXME: We should actually run this code path for append as well, but
+ // right now it creates problems with constraints (since we can end up
+ // trying to pass constraints from symbol to symbol).
+ if (amountCopied.isUnknown() && !isAppending) {
+ // Try to get a "hypothetical" string length symbol, which we can later
+ // set as a real value if that turns out to be the case.
+ amountCopied = getCStringLength(C, state, lenExpr, srcVal, true);
+ assert(!amountCopied.isUndef());
+
+ if (NonLoc *amountCopiedNL = dyn_cast<NonLoc>(&amountCopied)) {
+ if (lenValNL) {
+ // amountCopied <= lenVal
+ SVal copiedLessThanBound = svalBuilder.evalBinOpNN(state, BO_LE,
+ *amountCopiedNL,
+ *lenValNL,
+ cmpTy);
+ state = state->assume(cast<DefinedOrUnknownSVal>(copiedLessThanBound),
+ true);
+ if (!state)
+ return;
+ }
+
+ if (strLengthNL) {
+ // amountCopied <= strlen(source)
+ SVal copiedLessThanSrc = svalBuilder.evalBinOpNN(state, BO_LE,
+ *amountCopiedNL,
+ *strLengthNL,
+ cmpTy);
+ state = state->assume(cast<DefinedOrUnknownSVal>(copiedLessThanSrc),
+ true);
+ if (!state)
+ return;
+ }
+ }
+ }
+
+ } else {
+ // The function isn't bounded. The amount copied should match the length
+ // of the source buffer.
+ amountCopied = strLength;
}
+ assert(state);
+
+ // This represents the number of characters copied into the destination
+ // buffer. (It may not actually be the strlen if the destination buffer
+ // is not terminated.)
+ SVal finalStrLength = UnknownVal();
+
// If this is an appending function (strcat, strncat...) then set the
// string length to strlen(src) + strlen(dst) since the buffer will
// ultimately contain both.
if (isAppending) {
- // Get the string length of the destination, or give up.
+ // Get the string length of the destination. If the destination is memory
+ // that can't have a string length, we shouldn't be copying into it anyway.
SVal dstStrLength = getCStringLength(C, state, Dst, DstVal);
if (dstStrLength.isUndef())
return;
- NonLoc *srcStrLengthNL = dyn_cast<NonLoc>(&strLength);
+ NonLoc *srcStrLengthNL = dyn_cast<NonLoc>(&amountCopied);
NonLoc *dstStrLengthNL = dyn_cast<NonLoc>(&dstStrLength);
- // If src or dst cast to NonLoc is NULL, give up.
- if ((!srcStrLengthNL) || (!dstStrLengthNL))
- return;
+ // If we know both string lengths, we might know the final string length.
+ if (srcStrLengthNL && dstStrLengthNL) {
+ // Make sure the two lengths together don't overflow a size_t.
+ state = checkAdditionOverflow(C, state, *srcStrLengthNL, *dstStrLengthNL);
+ if (!state)
+ return;
+
+ finalStrLength = svalBuilder.evalBinOpNN(state, BO_Add, *srcStrLengthNL,
+ *dstStrLengthNL, sizeTy);
+ }
- QualType addTy = C.getSValBuilder().getContext().getSizeType();
+ // If we couldn't get a single value for the final string length,
+ // we can at least bound it by the individual lengths.
+ if (finalStrLength.isUnknown()) {
+ // Try to get a "hypothetical" string length symbol, which we can later
+ // set as a real value if that turns out to be the case.
+ finalStrLength = getCStringLength(C, state, CE, DstVal, true);
+ assert(!finalStrLength.isUndef());
+
+ if (NonLoc *finalStrLengthNL = dyn_cast<NonLoc>(&finalStrLength)) {
+ if (srcStrLengthNL) {
+ // finalStrLength >= srcStrLength
+ SVal sourceInResult = svalBuilder.evalBinOpNN(state, BO_GE,
+ *finalStrLengthNL,
+ *srcStrLengthNL,
+ cmpTy);
+ state = state->assume(cast<DefinedOrUnknownSVal>(sourceInResult),
+ true);
+ if (!state)
+ return;
+ }
+
+ if (dstStrLengthNL) {
+ // finalStrLength >= dstStrLength
+ SVal destInResult = svalBuilder.evalBinOpNN(state, BO_GE,
+ *finalStrLengthNL,
+ *dstStrLengthNL,
+ cmpTy);
+ state = state->assume(cast<DefinedOrUnknownSVal>(destInResult),
+ true);
+ if (!state)
+ return;
+ }
+ }
+ }
- strLength = C.getSValBuilder().evalBinOpNN(state, BO_Add,
- *srcStrLengthNL, *dstStrLengthNL,
- addTy);
+ } else {
+ // Otherwise, this is a copy-over function (strcpy, strncpy, ...), and
+ // the final string length will match the input string length.
+ finalStrLength = amountCopied;
}
+ // The final result of the function will either be a pointer past the last
+ // copied element, or a pointer to the start of the destination buffer.
SVal Result = (returnEnd ? UnknownVal() : DstVal);
+ assert(state);
+
// If the destination is a MemRegion, try to check for a buffer overflow and
// record the new string length.
if (loc::MemRegionVal *dstRegVal = dyn_cast<loc::MemRegionVal>(&DstVal)) {
- // If the length is known, we can check for an overflow.
- if (NonLoc *knownStrLength = dyn_cast<NonLoc>(&strLength)) {
- SVal lastElement =
- C.getSValBuilder().evalBinOpLN(state, BO_Add, *dstRegVal,
- *knownStrLength, Dst->getType());
+ QualType ptrTy = Dst->getType();
+
+ // If we have an exact value on a bounded copy, use that to check for
+ // overflows, rather than our estimate about how much is actually copied.
+ if (boundWarning) {
+ if (NonLoc *maxLastNL = dyn_cast<NonLoc>(&maxLastElementIndex)) {
+ SVal maxLastElement = svalBuilder.evalBinOpLN(state, BO_Add, *dstRegVal,
+ *maxLastNL, ptrTy);
+ state = CheckLocation(C, state, CE->getArg(2), maxLastElement,
+ boundWarning);
+ if (!state)
+ return;
+ }
+ }
- state = CheckLocation(C, state, Dst, lastElement, /* IsDst = */ true);
- if (!state)
- return;
+ // Then, if the final length is known...
+ if (NonLoc *knownStrLength = dyn_cast<NonLoc>(&finalStrLength)) {
+ SVal lastElement = svalBuilder.evalBinOpLN(state, BO_Add, *dstRegVal,
+ *knownStrLength, ptrTy);
+
+ // ...and we haven't checked the bound, we'll check the actual copy.
+ if (!boundWarning) {
+ const char * const warningMsg =
+ "String copy function overflows destination buffer";
+ state = CheckLocation(C, state, Dst, lastElement, warningMsg);
+ if (!state)
+ return;
+ }
// If this is a stpcpy-style copy, the last element is the return value.
if (returnEnd)
@@ -1107,16 +1463,25 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
// string, but that's still an improvement over blank invalidation.
state = InvalidateBuffer(C, state, Dst, *dstRegVal);
- // Set the C string length of the destination.
- state = setCStringLength(state, dstRegVal->getRegion(), strLength);
+ // Set the C string length of the destination, if we know it.
+ if (isBounded && !isAppending) {
+ // strncpy is annoying in that it doesn't guarantee to null-terminate
+ // the result string. If the original string didn't fit entirely inside
+ // the bound (including the null-terminator), we don't know how long the
+ // result is.
+ if (amountCopied != strLength)
+ finalStrLength = UnknownVal();
+ }
+ state = setCStringLength(state, dstRegVal->getRegion(), finalStrLength);
}
+ assert(state);
+
// If this is a stpcpy-style copy, but we were unable to check for a buffer
// overflow, we still need a result. Conjure a return value.
if (returnEnd && Result.isUnknown()) {
- SValBuilder &svalBuilder = C.getSValBuilder();
unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
- strLength = svalBuilder.getConjuredSymbolVal(NULL, CE, Count);
+ Result = svalBuilder.getConjuredSymbolVal(NULL, CE, Count);
}
// Set the return value.
@@ -1125,29 +1490,30 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
}
void CStringChecker::evalStrcmp(CheckerContext &C, const CallExpr *CE) const {
- //int strcmp(const char *restrict s1, const char *restrict s2);
+ //int strcmp(const char *s1, const char *s2);
evalStrcmpCommon(C, CE, /* isBounded = */ false, /* ignoreCase = */ false);
}
void CStringChecker::evalStrncmp(CheckerContext &C, const CallExpr *CE) const {
- //int strncmp(const char *restrict s1, const char *restrict s2, size_t n);
+ //int strncmp(const char *s1, const char *s2, size_t n);
evalStrcmpCommon(C, CE, /* isBounded = */ true, /* ignoreCase = */ false);
}
void CStringChecker::evalStrcasecmp(CheckerContext &C,
const CallExpr *CE) const {
- //int strcasecmp(const char *restrict s1, const char *restrict s2);
+ //int strcasecmp(const char *s1, const char *s2);
evalStrcmpCommon(C, CE, /* isBounded = */ false, /* ignoreCase = */ true);
}
void CStringChecker::evalStrncasecmp(CheckerContext &C,
const CallExpr *CE) const {
- //int strncasecmp(const char *restrict s1, const char *restrict s2, size_t n);
+ //int strncasecmp(const char *s1, const char *s2, size_t n);
evalStrcmpCommon(C, CE, /* isBounded = */ true, /* ignoreCase = */ true);
}
void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
bool isBounded, bool ignoreCase) const {
+ CurrentFunctionDescription = "string comparison function";
const GRState *state = C.getState();
// Check that the first string is non-null
@@ -1174,52 +1540,96 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
if (s2Length.isUndef())
return;
- // Get the string literal of the first string.
- const StringLiteral *s1StrLiteral = getCStringLiteral(C, state, s1, s1Val);
- if (!s1StrLiteral)
- return;
- llvm::StringRef s1StrRef = s1StrLiteral->getString();
+ // If we know the two buffers are the same, we know the result is 0.
+ // First, get the two buffers' addresses. Another checker will have already
+ // made sure they're not undefined.
+ DefinedOrUnknownSVal LV = cast<DefinedOrUnknownSVal>(s1Val);
+ DefinedOrUnknownSVal RV = cast<DefinedOrUnknownSVal>(s2Val);
+
+ // See if they are the same.
+ SValBuilder &svalBuilder = C.getSValBuilder();
+ DefinedOrUnknownSVal SameBuf = svalBuilder.evalEQ(state, LV, RV);
+ const GRState *StSameBuf, *StNotSameBuf;
+ llvm::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf);
+
+ // If the two arguments might be the same buffer, we know the result is 0,
+ // and we only need to check one size.
+ if (StSameBuf) {
+ StSameBuf = StSameBuf->BindExpr(CE, svalBuilder.makeZeroVal(CE->getType()));
+ C.addTransition(StSameBuf);
+
+ // If the two arguments are GUARANTEED to be the same, we're done!
+ if (!StNotSameBuf)
+ return;
+ }
+
+ assert(StNotSameBuf);
+ state = StNotSameBuf;
+
+ // At this point we can go about comparing the two buffers.
+ // For now, we only do this if they're both known string literals.
- // Get the string literal of the second string.
+ // Attempt to extract string literals from both expressions.
+ const StringLiteral *s1StrLiteral = getCStringLiteral(C, state, s1, s1Val);
const StringLiteral *s2StrLiteral = getCStringLiteral(C, state, s2, s2Val);
- if (!s2StrLiteral)
- return;
- llvm::StringRef s2StrRef = s2StrLiteral->getString();
+ bool canComputeResult = false;
+
+ if (s1StrLiteral && s2StrLiteral) {
+ llvm::StringRef s1StrRef = s1StrLiteral->getString();
+ llvm::StringRef s2StrRef = s2StrLiteral->getString();
+
+ if (isBounded) {
+ // Get the max number of characters to compare.
+ const Expr *lenExpr = CE->getArg(2);
+ SVal lenVal = state->getSVal(lenExpr);
+
+ // If the length is known, we can get the right substrings.
+ if (const llvm::APSInt *len = svalBuilder.getKnownValue(state, lenVal)) {
+ // Create substrings of each to compare the prefix.
+ s1StrRef = s1StrRef.substr(0, (size_t)len->getZExtValue());
+ s2StrRef = s2StrRef.substr(0, (size_t)len->getZExtValue());
+ canComputeResult = true;
+ }
+ } else {
+ // This is a normal, unbounded strcmp.
+ canComputeResult = true;
+ }
- int result;
- if (isBounded) {
- // Get the max number of characters to compare.
- const Expr *lenExpr = CE->getArg(2);
- SVal lenVal = state->getSVal(lenExpr);
+ if (canComputeResult) {
+ // Real strcmp stops at null characters.
+ size_t s1Term = s1StrRef.find('\0');
+ if (s1Term != llvm::StringRef::npos)
+ s1StrRef = s1StrRef.substr(0, s1Term);
- // Dynamically cast the length to a ConcreteInt. If it is not a ConcreteInt
- // then give up, otherwise get the value and use it as the bounds.
- nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(&lenVal);
- if (!CI)
- return;
- llvm::APSInt lenInt(CI->getValue());
+ size_t s2Term = s2StrRef.find('\0');
+ if (s2Term != llvm::StringRef::npos)
+ s2StrRef = s2StrRef.substr(0, s2Term);
+
+ // Use StringRef's comparison methods to compute the actual result.
+ int result;
- // Create substrings of each to compare the prefix.
- s1StrRef = s1StrRef.substr(0, (size_t)lenInt.getLimitedValue());
- s2StrRef = s2StrRef.substr(0, (size_t)lenInt.getLimitedValue());
+ if (ignoreCase) {
+ // Compare string 1 to string 2 the same way strcasecmp() does.
+ result = s1StrRef.compare_lower(s2StrRef);
+ } else {
+ // Compare string 1 to string 2 the same way strcmp() does.
+ result = s1StrRef.compare(s2StrRef);
+ }
+
+ // Build the SVal of the comparison and bind the return value.
+ SVal resultVal = svalBuilder.makeIntVal(result, CE->getType());
+ state = state->BindExpr(CE, resultVal);
+ }
}
- if (ignoreCase) {
- // Compare string 1 to string 2 the same way strcasecmp() does.
- result = s1StrRef.compare_lower(s2StrRef);
- } else {
- // Compare string 1 to string 2 the same way strcmp() does.
- result = s1StrRef.compare(s2StrRef);
+ if (!canComputeResult) {
+ // Conjure a symbolic value. It's the best we can do.
+ unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
+ SVal resultVal = svalBuilder.getConjuredSymbolVal(NULL, CE, Count);
+ state = state->BindExpr(CE, resultVal);
}
-
- // Build the SVal of the comparison to bind the return value.
- SValBuilder &svalBuilder = C.getSValBuilder();
- QualType intTy = svalBuilder.getContext().IntTy;
- SVal resultVal = svalBuilder.makeIntVal(result, intTy);
- // Bind the return value of the expression.
- // Set the return value.
- state = state->BindExpr(CE, resultVal);
+ // Record this as a possible path.
C.addTransition(state);
}
@@ -1251,7 +1661,7 @@ bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
.Cases("memcmp", "bcmp", &CStringChecker::evalMemcmp)
.Cases("memmove", "__memmove_chk", &CStringChecker::evalMemmove)
.Cases("strcpy", "__strcpy_chk", &CStringChecker::evalStrcpy)
- //.Cases("strncpy", "__strncpy_chk", &CStringChecker::evalStrncpy)
+ .Cases("strncpy", "__strncpy_chk", &CStringChecker::evalStrncpy)
.Cases("stpcpy", "__stpcpy_chk", &CStringChecker::evalStpcpy)
.Cases("strcat", "__strcat_chk", &CStringChecker::evalStrcat)
.Cases("strncat", "__strncat_chk", &CStringChecker::evalStrncat)
@@ -1268,6 +1678,10 @@ bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
if (!evalFunction)
return false;
+ // Make sure each function sets its own description.
+ // (But don't bother in a release build.)
+ assert(!(CurrentFunctionDescription = NULL));
+
// Check and evaluate the call.
(this->*evalFunction)(C, CE);
return true;
@@ -1373,8 +1787,10 @@ void CStringChecker::checkLiveSymbols(const GRState *state,
for (CStringLength::EntryMap::iterator I = Entries.begin(), E = Entries.end();
I != E; ++I) {
SVal Len = I.getData();
- if (SymbolRef Sym = Len.getAsSymbol())
- SR.markInUse(Sym);
+
+ for (SVal::symbol_iterator si = Len.symbol_begin(), se = Len.symbol_end();
+ si != se; ++si)
+ SR.markInUse(*si);
}
}
diff --git a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
index dfe0a0e6f50a..6c3dfacec331 100644
--- a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
@@ -282,7 +282,7 @@ void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
static bool supportsNilWithFloatRet(const llvm::Triple &triple) {
return triple.getVendor() == llvm::Triple::Apple &&
- (triple.getDarwinMajorNumber() >= 9 ||
+ (!triple.isMacOSXVersionLT(10,5) ||
triple.getArch() == llvm::Triple::arm ||
triple.getArch() == llvm::Triple::thumb);
}
diff --git a/lib/StaticAnalyzer/Checkers/Checkers.td b/lib/StaticAnalyzer/Checkers/Checkers.td
index 1a71fc4074ba..2c196b597b7d 100644
--- a/lib/StaticAnalyzer/Checkers/Checkers.td
+++ b/lib/StaticAnalyzer/Checkers/Checkers.td
@@ -168,10 +168,6 @@ def ReturnUndefChecker : Checker<"UndefReturn">,
let ParentPackage = CplusplusExperimental in {
-def CStringChecker : Checker<"CString">,
- HelpText<"Check calls to functions in <string.h>">,
- DescFile<"CStringChecker.cpp">;
-
def IteratorsChecker : Checker<"Iterators">,
HelpText<"Check improper uses of STL vector iterators">,
DescFile<"IteratorsChecker.cpp">;
@@ -244,6 +240,10 @@ def ChrootChecker : Checker<"Chroot">,
HelpText<"Check improper use of chroot">,
DescFile<"ChrootChecker.cpp">;
+def CStringChecker : Checker<"CString">,
+ HelpText<"Check calls to functions in <string.h>">,
+ DescFile<"CStringChecker.cpp">;
+
def MallocChecker : Checker<"Malloc">,
HelpText<"Check for potential memory leaks, double free, and use-after-free problems">,
DescFile<"MallocChecker.cpp">;
diff --git a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
index bc1d823dde03..ec2a88a55681 100644
--- a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
@@ -254,13 +254,13 @@ public:
return;
if (Expr* E = V->getInit()) {
+ while (ExprWithCleanups *exprClean = dyn_cast<ExprWithCleanups>(E))
+ E = exprClean->getSubExpr();
+
// Don't warn on C++ objects (yet) until we can show that their
// constructors/destructors don't have side effects.
if (isa<CXXConstructExpr>(E))
return;
-
- if (isa<ExprWithCleanups>(E))
- return;
// A dead initialization is a variable that is dead after it
// is initialized. We don't flag warnings for those variables
diff --git a/lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp b/lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp
index e4e5f54770b3..de6da4f8c377 100644
--- a/lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp
@@ -237,8 +237,11 @@ const GRState *IteratorsChecker::invalidateIterators(const GRState *state,
const GRState *IteratorsChecker::handleAssign(const GRState *state,
const Expr *lexp, const Expr *rexp, const LocationContext *LC) const {
// Skip the cast if present.
- if (isa<ImplicitCastExpr>(lexp))
- lexp = dyn_cast<ImplicitCastExpr>(lexp)->getSubExpr();
+ if (const MaterializeTemporaryExpr *M
+ = dyn_cast<MaterializeTemporaryExpr>(lexp))
+ lexp = M->GetTemporaryExpr();
+ if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(lexp))
+ lexp = ICE->getSubExpr();
SVal sv = state->getSVal(lexp);
const MemRegion *MR = sv.getAsRegion();
if (!MR)
@@ -260,8 +263,11 @@ const GRState *IteratorsChecker::handleAssign(const GRState *state,
const MemRegion *MR, const Expr *rexp, const LocationContext *LC) const {
// Assume unknown until we find something definite.
state = state->set<IteratorState>(MR, RefState::getUnknown());
- if (isa<ImplicitCastExpr>(rexp))
- rexp = dyn_cast<ImplicitCastExpr>(rexp)->getSubExpr();
+ if (const MaterializeTemporaryExpr *M
+ = dyn_cast<MaterializeTemporaryExpr>(rexp))
+ rexp = M->GetTemporaryExpr();
+ if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(rexp))
+ rexp = ICE->getSubExpr();
// Need to handle three cases: MemberCall, copy, copy with addition.
if (const CallExpr *CE = dyn_cast<CallExpr>(rexp)) {
// Handle MemberCall.
@@ -347,8 +353,10 @@ const DeclRefExpr *IteratorsChecker::getDeclRefExpr(const Expr *E) const {
E = CE->getArg(0);
}
}
- if (isa<ImplicitCastExpr>(E))
- E = dyn_cast<ImplicitCastExpr>(E)->getSubExpr();
+ if (const MaterializeTemporaryExpr *M = dyn_cast<MaterializeTemporaryExpr>(E))
+ E = M->GetTemporaryExpr();
+ if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E))
+ E = ICE->getSubExpr();
// If it isn't one of our types, don't do anything.
if (getTemplateKind(E->getType()) != VectorIteratorKind)
return NULL;
@@ -520,8 +528,11 @@ void IteratorsChecker::checkPreStmt(const DeclStmt *DS,
if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(InitEx)) {
if (CE->getNumArgs() == 1) {
const Expr *E = CE->getArg(0);
- if (isa<ImplicitCastExpr>(E))
- InitEx = dyn_cast<ImplicitCastExpr>(E)->getSubExpr();
+ if (const MaterializeTemporaryExpr *M
+ = dyn_cast<MaterializeTemporaryExpr>(E))
+ E = M->GetTemporaryExpr();
+ if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E))
+ InitEx = ICE->getSubExpr();
state = handleAssign(state, MR, InitEx,
C.getPredecessor()->getLocationContext());
}
diff --git a/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
index 12ce86613ddc..f8d076b54e3d 100644
--- a/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
@@ -31,22 +31,17 @@ using namespace ento;
namespace {
class MacOSXAPIChecker : public Checker< check::PreStmt<CallExpr> > {
- enum SubChecks {
- DispatchOnce = 0,
- DispatchOnceF,
- NumChecks
- };
-
- mutable BugType *BTypes[NumChecks];
+ mutable llvm::OwningPtr<BugType> BT_dispatchOnce;
public:
- MacOSXAPIChecker() { memset(BTypes, 0, sizeof(*BTypes) * NumChecks); }
- ~MacOSXAPIChecker() {
- for (unsigned i=0; i != NumChecks; ++i)
- delete BTypes[i];
- }
-
void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
+
+ void CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
+ const IdentifierInfo *FI) const;
+
+ typedef void (MacOSXAPIChecker::*SubChecker)(CheckerContext &,
+ const CallExpr *,
+ const IdentifierInfo *) const;
};
} //end anonymous namespace
@@ -54,16 +49,8 @@ public:
// dispatch_once and dispatch_once_f
//===----------------------------------------------------------------------===//
-static void CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
- BugType *&BT, const IdentifierInfo *FI) {
-
- if (!BT) {
- llvm::SmallString<128> S;
- llvm::raw_svector_ostream os(S);
- os << "Improper use of '" << FI->getName() << '\'';
- BT = new BugType(os.str(), "Mac OS X API");
- }
-
+void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
+ const IdentifierInfo *FI) const {
if (CE->getNumArgs() < 1)
return;
@@ -78,6 +65,10 @@ static void CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
if (!N)
return;
+ if (!BT_dispatchOnce)
+ BT_dispatchOnce.reset(new BugType("Improper use of 'dispatch_once'",
+ "Mac OS X API"));
+
llvm::SmallString<256> S;
llvm::raw_svector_ostream os(S);
os << "Call to '" << FI->getName() << "' uses";
@@ -90,7 +81,7 @@ static void CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace()))
os << " Perhaps you intended to declare the variable as 'static'?";
- EnhancedBugReport *report = new EnhancedBugReport(*BT, os.str(), N);
+ RangedBugReport *report = new RangedBugReport(*BT_dispatchOnce, os.str(), N);
report->addRange(CE->getArg(0)->getSourceRange());
C.EmitReport(report);
}
@@ -99,47 +90,29 @@ static void CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
// Central dispatch function.
//===----------------------------------------------------------------------===//
-typedef void (*SubChecker)(CheckerContext &C, const CallExpr *CE, BugType *&BT,
- const IdentifierInfo *FI);
-namespace {
- class SubCheck {
- SubChecker SC;
- BugType **BT;
- public:
- SubCheck(SubChecker sc, BugType *& bt) : SC(sc), BT(&bt) {}
- SubCheck() : SC(NULL), BT(NULL) {}
-
- void run(CheckerContext &C, const CallExpr *CE,
- const IdentifierInfo *FI) const {
- if (SC)
- SC(C, CE, *BT, FI);
- }
- };
-} // end anonymous namespace
-
void MacOSXAPIChecker::checkPreStmt(const CallExpr *CE,
CheckerContext &C) const {
- // FIXME: Mostly copy and paste from UnixAPIChecker. Should refactor.
+ // FIXME: This sort of logic is common to several checkers, including
+ // UnixAPIChecker, PthreadLockChecker, and CStringChecker. Should refactor.
const GRState *state = C.getState();
const Expr *Callee = CE->getCallee();
- const FunctionTextRegion *Fn =
- dyn_cast_or_null<FunctionTextRegion>(state->getSVal(Callee).getAsRegion());
+ const FunctionDecl *Fn = state->getSVal(Callee).getAsFunctionDecl();
if (!Fn)
return;
- const IdentifierInfo *FI = Fn->getDecl()->getIdentifier();
+ const IdentifierInfo *FI = Fn->getIdentifier();
if (!FI)
return;
- const SubCheck &SC =
- llvm::StringSwitch<SubCheck>(FI->getName())
- .Case("dispatch_once", SubCheck(CheckDispatchOnce, BTypes[DispatchOnce]))
- .Case("dispatch_once_f", SubCheck(CheckDispatchOnce,
- BTypes[DispatchOnceF]))
- .Default(SubCheck());
+ SubChecker SC =
+ llvm::StringSwitch<SubChecker>(FI->getName())
+ .Cases("dispatch_once", "dispatch_once_f",
+ &MacOSXAPIChecker::CheckDispatchOnce)
+ .Default(NULL);
- SC.run(C, CE, FI);
+ if (SC)
+ (this->*SC)(C, CE, FI);
}
//===----------------------------------------------------------------------===//
diff --git a/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index 07de8706df24..73ce359edc3e 100644
--- a/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -121,6 +121,11 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
return;
if (R->hasStackStorage()) {
+ // Automatic reference counting automatically copies blocks.
+ if (C.getASTContext().getLangOptions().ObjCAutoRefCount &&
+ isa<BlockDataRegion>(R))
+ return;
+
EmitStackError(C, R, RetE);
return;
}
@@ -135,12 +140,13 @@ void StackAddrEscapeChecker::checkEndPath(EndOfFunctionNodeBuilder &B,
// a memory region in the stack space.
class CallBack : public StoreManager::BindingsHandler {
private:
+ ExprEngine &Eng;
const StackFrameContext *CurSFC;
public:
llvm::SmallVector<std::pair<const MemRegion*, const MemRegion*>, 10> V;
- CallBack(const LocationContext *LCtx)
- : CurSFC(LCtx->getCurrentStackFrame()) {}
+ CallBack(ExprEngine &Eng, const LocationContext *LCtx)
+ : Eng(Eng), CurSFC(LCtx->getCurrentStackFrame()) {}
bool HandleBinding(StoreManager &SMgr, Store store,
const MemRegion *region, SVal val) {
@@ -151,7 +157,13 @@ void StackAddrEscapeChecker::checkEndPath(EndOfFunctionNodeBuilder &B,
const MemRegion *vR = val.getAsRegion();
if (!vR)
return true;
-
+
+ // Under automated retain release, it is okay to assign a block
+ // directly to a global variable.
+ if (Eng.getContext().getLangOptions().ObjCAutoRefCount &&
+ isa<BlockDataRegion>(vR))
+ return true;
+
if (const StackSpaceRegion *SSR =
dyn_cast<StackSpaceRegion>(vR->getMemorySpace())) {
// If the global variable holds a location in the current stack frame,
@@ -164,7 +176,7 @@ void StackAddrEscapeChecker::checkEndPath(EndOfFunctionNodeBuilder &B,
}
};
- CallBack cb(B.getPredecessor()->getLocationContext());
+ CallBack cb(Eng, B.getPredecessor()->getLocationContext());
state->getStateManager().getStoreManager().iterBindings(state->getStore(),cb);
if (cb.V.empty())
diff --git a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
index 48d7c367a96d..0ecc391f3e8f 100644
--- a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
@@ -28,26 +28,18 @@ using llvm::Optional;
namespace {
class UnixAPIChecker : public Checker< check::PreStmt<CallExpr> > {
- enum SubChecks {
- OpenFn = 0,
- PthreadOnceFn = 1,
- MallocZero = 2,
- NumChecks
- };
-
- mutable BugType *BTypes[NumChecks];
-
-public:
+ mutable llvm::OwningPtr<BugType> BT_open, BT_pthreadOnce, BT_mallocZero;
mutable Optional<uint64_t> Val_O_CREAT;
public:
- UnixAPIChecker() { memset(BTypes, 0, sizeof(*BTypes) * NumChecks); }
- ~UnixAPIChecker() {
- for (unsigned i=0; i != NumChecks; ++i)
- delete BTypes[i];
- }
-
void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
+
+ void CheckOpen(CheckerContext &C, const CallExpr *CE) const;
+ void CheckPthreadOnce(CheckerContext &C, const CallExpr *CE) const;
+ void CheckMallocZero(CheckerContext &C, const CallExpr *CE) const;
+
+ typedef void (UnixAPIChecker::*SubChecker)(CheckerContext &,
+ const CallExpr *) const;
};
} //end anonymous namespace
@@ -55,23 +47,23 @@ public:
// Utility functions.
//===----------------------------------------------------------------------===//
-static inline void LazyInitialize(BugType *&BT, const char *name) {
+static inline void LazyInitialize(llvm::OwningPtr<BugType> &BT,
+ const char *name) {
if (BT)
return;
- BT = new BugType(name, "Unix API");
+ BT.reset(new BugType(name, "Unix API"));
}
//===----------------------------------------------------------------------===//
// "open" (man 2 open)
//===----------------------------------------------------------------------===//
-static void CheckOpen(CheckerContext &C, const UnixAPIChecker &UC,
- const CallExpr *CE, BugType *&BT) {
+void UnixAPIChecker::CheckOpen(CheckerContext &C, const CallExpr *CE) const {
// The definition of O_CREAT is platform specific. We need a better way
// of querying this information from the checking environment.
- if (!UC.Val_O_CREAT.hasValue()) {
+ if (!Val_O_CREAT.hasValue()) {
if (C.getASTContext().Target.getTriple().getVendor() == llvm::Triple::Apple)
- UC.Val_O_CREAT = 0x0200;
+ Val_O_CREAT = 0x0200;
else {
// FIXME: We need a more general way of getting the O_CREAT value.
// We could possibly grovel through the preprocessor state, but
@@ -80,8 +72,6 @@ static void CheckOpen(CheckerContext &C, const UnixAPIChecker &UC,
}
}
- LazyInitialize(BT, "Improper use of 'open'");
-
// Look at the 'oflags' argument for the O_CREAT flag.
const GRState *state = C.getState();
@@ -101,7 +91,7 @@ static void CheckOpen(CheckerContext &C, const UnixAPIChecker &UC,
}
NonLoc oflags = cast<NonLoc>(V);
NonLoc ocreateFlag =
- cast<NonLoc>(C.getSValBuilder().makeIntVal(UC.Val_O_CREAT.getValue(),
+ cast<NonLoc>(C.getSValBuilder().makeIntVal(Val_O_CREAT.getValue(),
oflagsEx->getType()));
SVal maskedFlagsUC = C.getSValBuilder().evalBinOpNN(state, BO_And,
oflags, ocreateFlag,
@@ -124,8 +114,10 @@ static void CheckOpen(CheckerContext &C, const UnixAPIChecker &UC,
if (!N)
return;
- EnhancedBugReport *report =
- new EnhancedBugReport(*BT,
+ LazyInitialize(BT_open, "Improper use of 'open'");
+
+ RangedBugReport *report =
+ new RangedBugReport(*BT_open,
"Call to 'open' requires a third argument when "
"the 'O_CREAT' flag is set", N);
report->addRange(oflagsEx->getSourceRange());
@@ -137,14 +129,12 @@ static void CheckOpen(CheckerContext &C, const UnixAPIChecker &UC,
// pthread_once
//===----------------------------------------------------------------------===//
-static void CheckPthreadOnce(CheckerContext &C, const UnixAPIChecker &,
- const CallExpr *CE, BugType *&BT) {
+void UnixAPIChecker::CheckPthreadOnce(CheckerContext &C,
+ const CallExpr *CE) const {
// This is similar to 'CheckDispatchOnce' in the MacOSXAPIChecker.
// They can possibly be refactored.
- LazyInitialize(BT, "Improper use of 'pthread_once'");
-
if (CE->getNumArgs() < 1)
return;
@@ -171,7 +161,9 @@ static void CheckPthreadOnce(CheckerContext &C, const UnixAPIChecker &,
if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace()))
os << " Perhaps you intended to declare the variable as 'static'?";
- EnhancedBugReport *report = new EnhancedBugReport(*BT, os.str(), N);
+ LazyInitialize(BT_pthreadOnce, "Improper use of 'pthread_once'");
+
+ RangedBugReport *report = new RangedBugReport(*BT_pthreadOnce, os.str(), N);
report->addRange(CE->getArg(0)->getSourceRange());
C.EmitReport(report);
}
@@ -182,8 +174,8 @@ static void CheckPthreadOnce(CheckerContext &C, const UnixAPIChecker &,
// FIXME: Eventually this should be rolled into the MallocChecker, but this
// check is more basic and is valuable for widespread use.
-static void CheckMallocZero(CheckerContext &C, const UnixAPIChecker &UC,
- const CallExpr *CE, BugType *&BT) {
+void UnixAPIChecker::CheckMallocZero(CheckerContext &C,
+ const CallExpr *CE) const {
// Sanity check that malloc takes one argument.
if (CE->getNumArgs() != 1)
@@ -208,11 +200,11 @@ static void CheckMallocZero(CheckerContext &C, const UnixAPIChecker &UC,
// FIXME: Add reference to CERT advisory, and/or C99 standard in bug
// output.
- LazyInitialize(BT, "Undefined allocation of 0 bytes");
+ LazyInitialize(BT_mallocZero, "Undefined allocation of 0 bytes");
EnhancedBugReport *report =
- new EnhancedBugReport(*BT, "Call to 'malloc' has an allocation size"
- " of 0 bytes", N);
+ new EnhancedBugReport(*BT_mallocZero, "Call to 'malloc' has an allocation"
+ " size of 0 bytes", N);
report->addRange(CE->getArg(0)->getSourceRange());
report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
CE->getArg(0));
@@ -230,51 +222,29 @@ static void CheckMallocZero(CheckerContext &C, const UnixAPIChecker &UC,
// Central dispatch function.
//===----------------------------------------------------------------------===//
-typedef void (*SubChecker)(CheckerContext &C, const UnixAPIChecker &UC,
- const CallExpr *CE, BugType *&BT);
-namespace {
- class SubCheck {
- SubChecker SC;
- const UnixAPIChecker *UC;
- BugType **BT;
- public:
- SubCheck(SubChecker sc, const UnixAPIChecker *uc, BugType *& bt)
- : SC(sc), UC(uc), BT(&bt) {}
- SubCheck() : SC(NULL), UC(NULL), BT(NULL) {}
-
- void run(CheckerContext &C, const CallExpr *CE) const {
- if (SC)
- SC(C, *UC, CE, *BT);
- }
- };
-} // end anonymous namespace
-
void UnixAPIChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const {
// Get the callee. All the functions we care about are C functions
// with simple identifiers.
const GRState *state = C.getState();
const Expr *Callee = CE->getCallee();
- const FunctionTextRegion *Fn =
- dyn_cast_or_null<FunctionTextRegion>(state->getSVal(Callee).getAsRegion());
+ const FunctionDecl *Fn = state->getSVal(Callee).getAsFunctionDecl();
if (!Fn)
return;
- const IdentifierInfo *FI = Fn->getDecl()->getIdentifier();
+ const IdentifierInfo *FI = Fn->getIdentifier();
if (!FI)
return;
- const SubCheck &SC =
- llvm::StringSwitch<SubCheck>(FI->getName())
- .Case("open",
- SubCheck(CheckOpen, this, BTypes[OpenFn]))
- .Case("pthread_once",
- SubCheck(CheckPthreadOnce, this, BTypes[PthreadOnceFn]))
- .Case("malloc",
- SubCheck(CheckMallocZero, this, BTypes[MallocZero]))
- .Default(SubCheck());
-
- SC.run(C, CE);
+ SubChecker SC =
+ llvm::StringSwitch<SubChecker>(FI->getName())
+ .Case("open", &UnixAPIChecker::CheckOpen)
+ .Case("pthread_once", &UnixAPIChecker::CheckPthreadOnce)
+ .Case("malloc", &UnixAPIChecker::CheckMallocZero)
+ .Default(NULL);
+
+ if (SC)
+ (this->*SC)(C, CE);
}
//===----------------------------------------------------------------------===//
diff --git a/lib/StaticAnalyzer/Core/CFRefCount.cpp b/lib/StaticAnalyzer/Core/CFRefCount.cpp
index 0512e2f08d04..bf5302920819 100644
--- a/lib/StaticAnalyzer/Core/CFRefCount.cpp
+++ b/lib/StaticAnalyzer/Core/CFRefCount.cpp
@@ -126,6 +126,7 @@ public:
/// ArgEffect is used to summarize a function/method call's effect on a
/// particular argument.
enum ArgEffect { Autorelease, Dealloc, DecRef, DecRefMsg, DoNothing,
+ DecRefBridgedTransfered,
DoNothingByRef, IncRefMsg, IncRef, MakeCollectable, MayEscape,
NewAutoreleasePool, SelfOwn, StopTracking };
@@ -148,7 +149,8 @@ namespace {
class RetEffect {
public:
enum Kind { NoRet, Alias, OwnedSymbol, OwnedAllocatedSymbol,
- NotOwnedSymbol, GCNotOwnedSymbol, ReceiverAlias,
+ NotOwnedSymbol, GCNotOwnedSymbol, ARCNotOwnedSymbol,
+ ReceiverAlias,
OwnedWhenTrackedReceiver };
enum ObjKind { CF, ObjC, AnyObj };
@@ -195,7 +197,9 @@ public:
static RetEffect MakeGCNotOwned() {
return RetEffect(GCNotOwnedSymbol, ObjC);
}
-
+ static RetEffect MakeARCNotOwned() {
+ return RetEffect(ARCNotOwnedSymbol, ObjC);
+ }
static RetEffect MakeNoRet() {
return RetEffect(NoRet);
}
@@ -636,6 +640,9 @@ class RetainSummaryManager {
/// GCEnabled - Records whether or not the analyzed code runs in GC mode.
const bool GCEnabled;
+ /// Records whether or not the analyzed code runs in ARC mode.
+ const bool ARCEnabled;
+
/// FuncSummaries - A map from FunctionDecls to summaries.
FuncSummariesTy FuncSummaries;
@@ -788,14 +795,20 @@ private:
public:
- RetainSummaryManager(ASTContext& ctx, bool gcenabled)
+ RetainSummaryManager(ASTContext& ctx, bool gcenabled, bool usesARC)
: Ctx(ctx),
CFDictionaryCreateII(&ctx.Idents.get("CFDictionaryCreate")),
- GCEnabled(gcenabled), AF(BPAlloc), ScratchArgs(AF.getEmptyMap()),
- ObjCAllocRetE(gcenabled ? RetEffect::MakeGCNotOwned()
- : RetEffect::MakeOwned(RetEffect::ObjC, true)),
- ObjCInitRetE(gcenabled ? RetEffect::MakeGCNotOwned()
- : RetEffect::MakeOwnedWhenTrackedReceiver()),
+ GCEnabled(gcenabled),
+ ARCEnabled(usesARC),
+ AF(BPAlloc), ScratchArgs(AF.getEmptyMap()),
+ ObjCAllocRetE(gcenabled
+ ? RetEffect::MakeGCNotOwned()
+ : (usesARC ? RetEffect::MakeARCNotOwned()
+ : RetEffect::MakeOwned(RetEffect::ObjC, true))),
+ ObjCInitRetE(gcenabled
+ ? RetEffect::MakeGCNotOwned()
+ : (usesARC ? RetEffect::MakeARCNotOwned()
+ : RetEffect::MakeOwnedWhenTrackedReceiver())),
DefaultSummary(AF.getEmptyMap() /* per-argument effects (none) */,
RetEffect::MakeNoRet() /* return effect */,
MayEscape, /* default argument effect */
@@ -871,6 +884,10 @@ public:
bool isGCEnabled() const { return GCEnabled; }
+ bool isARCEnabled() const { return ARCEnabled; }
+
+ bool isARCorGCEnabled() const { return GCEnabled || ARCEnabled; }
+
RetainSummary *copySummary(RetainSummary *OldSumm) {
RetainSummary *Summ = (RetainSummary*) BPAlloc.Allocate<RetainSummary>();
new (Summ) RetainSummary(*OldSumm);
@@ -1118,8 +1135,7 @@ RetainSummary* RetainSummaryManager::getSummary(const FunctionDecl* FD) {
RetainSummary*
RetainSummaryManager::getCFCreateGetRuleSummary(const FunctionDecl* FD,
StringRef FName) {
- if (FName.find("Create") != StringRef::npos ||
- FName.find("Copy") != StringRef::npos)
+ if (coreFoundation::followsCreateRule(FName))
return getCFSummaryCreateRule(FD);
return getCFSummaryGetRule(FD);
@@ -1189,7 +1205,8 @@ RetainSummaryManager::getInitMethodSummary(QualType RetTy) {
assert(ScratchArgs.isEmpty());
// 'init' methods conceptually return a newly allocated object and claim
// the receiver.
- if (cocoa::isCocoaObjectRef(RetTy) || cocoa::isCFObjectRef(RetTy))
+ if (cocoa::isCocoaObjectRef(RetTy) ||
+ coreFoundation::isCFObjectRef(RetTy))
return getPersistentSummary(ObjCInitRetE, DecRefMsg);
return getDefaultSummary();
@@ -1332,15 +1349,15 @@ RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl* MD,
if (cocoa::isCocoaObjectRef(RetTy)) {
// EXPERIMENTAL: assume the Cocoa conventions for all objects returned
// by instance methods.
- RetEffect E = cocoa::followsFundamentalRule(S)
+ RetEffect E = cocoa::followsFundamentalRule(S, MD)
? ObjCAllocRetE : RetEffect::MakeNotOwned(RetEffect::ObjC);
return getPersistentSummary(E, ReceiverEff, MayEscape);
}
// Look for methods that return an owned core foundation object.
- if (cocoa::isCFObjectRef(RetTy)) {
- RetEffect E = cocoa::followsFundamentalRule(S)
+ if (coreFoundation::isCFObjectRef(RetTy)) {
+ RetEffect E = cocoa::followsFundamentalRule(S, MD)
? RetEffect::MakeOwned(RetEffect::CF, true)
: RetEffect::MakeNotOwned(RetEffect::CF);
@@ -1411,7 +1428,7 @@ RetainSummaryManager::getInstanceMethodSummary(Selector S,
assert(ScratchArgs.isEmpty());
// "initXXX": pass-through for receiver.
- if (cocoa::deriveNamingConvention(S) == cocoa::InitRule)
+ if (cocoa::deriveNamingConvention(S, MD) == cocoa::InitRule)
Summ = getInitMethodSummary(RetTy);
else
Summ = getCommonMethodSummary(MD, S, RetTy);
@@ -1654,7 +1671,6 @@ public:
const char* nl, const char* sep);
};
-private:
typedef llvm::DenseMap<const ExplodedNode*, const RetainSummary*>
SummaryLogTy;
@@ -1691,7 +1707,7 @@ private:
public:
CFRefCount(ASTContext& Ctx, bool gcenabled, const LangOptions& lopts)
- : Summaries(Ctx, gcenabled),
+ : Summaries(Ctx, gcenabled, (bool)lopts.ObjCAutoRefCount),
LOpts(lopts), useAfterRelease(0), releaseNotOwned(0),
deallocGC(0), deallocNotOwned(0),
leakWithinFunction(0), leakAtReturn(0), overAutorelease(0),
@@ -1706,6 +1722,8 @@ public:
}
bool isGCEnabled() const { return Summaries.isGCEnabled(); }
+ bool isARCorGCEnabled() const { return Summaries.isARCorGCEnabled(); }
+
const LangOptions& getLangOptions() const { return LOpts; }
const RetainSummary *getSummaryOfNode(const ExplodedNode *N) const {
@@ -1907,7 +1925,7 @@ namespace {
CFRefBug(tf, "Method should return an owned object") {}
const char *getDescription() const {
- return "Object with +0 retain counts returned to caller where a +1 "
+ return "Object with a +0 retain count returned to caller where a +1 "
"(owning) retain count is expected";
}
};
@@ -2094,7 +2112,7 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N,
if (static_cast<CFRefBug&>(getBugType()).getTF().isGCEnabled()) {
assert(CurrV.getObjKind() == RetEffect::CF);
- os << " "
+ os << ". "
"Core Foundation objects are not automatically garbage collected.";
}
}
@@ -2416,14 +2434,14 @@ CFRefLeakReport::getEndPath(BugReporterContext& BRC,
if (RV->getKind() == RefVal::ErrorLeakReturned) {
// FIXME: Per comments in rdar://6320065, "create" only applies to CF
- // ojbects. Only "copy", "alloc", "retain" and "new" transfer ownership
+ // objects. Only "copy", "alloc", "retain" and "new" transfer ownership
// to the caller for NS objects.
const Decl *D = &EndN->getCodeDecl();
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
os << " is returned from a method whose name ('"
<< MD->getSelector().getAsString()
<< "') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'."
- " This violates the naming convention rules "
+ " This violates the naming convention rules"
" given in the Memory Management Guide for Cocoa";
}
else {
@@ -2431,7 +2449,7 @@ CFRefLeakReport::getEndPath(BugReporterContext& BRC,
os << " is return from a function whose name ('"
<< FD->getNameAsString()
<< "') does not contain 'Copy' or 'Create'. This violates the naming"
- " convention rules given the Memory Management Guide for Core "
+ " convention rules given the Memory Management Guide for Core"
" Foundation";
}
}
@@ -2777,6 +2795,7 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst,
}
case RetEffect::GCNotOwnedSymbol:
+ case RetEffect::ARCNotOwnedSymbol:
case RetEffect::NotOwnedSymbol: {
unsigned Count = Builder.getCurrentBlockCount();
SValBuilder &svalBuilder = Eng.getSValBuilder();
@@ -3103,8 +3122,8 @@ const GRState * CFRefCount::Update(const GRState * state, SymbolRef sym,
// In GC mode [... release] and [... retain] do nothing.
switch (E) {
default: break;
- case IncRefMsg: E = isGCEnabled() ? DoNothing : IncRef; break;
- case DecRefMsg: E = isGCEnabled() ? DoNothing : DecRef; break;
+ case IncRefMsg: E = isARCorGCEnabled() ? DoNothing : IncRef; break;
+ case DecRefMsg: E = isARCorGCEnabled() ? DoNothing : DecRef; break;
case MakeCollectable: E = isGCEnabled() ? DecRef : DoNothing; break;
case NewAutoreleasePool: E = isGCEnabled() ? DoNothing :
NewAutoreleasePool; break;
@@ -3118,9 +3137,13 @@ const GRState * CFRefCount::Update(const GRState * state, SymbolRef sym,
}
switch (E) {
- default:
- assert (false && "Unhandled CFRef transition.");
-
+ case DecRefMsg:
+ case IncRefMsg:
+ case MakeCollectable:
+ assert(false &&
+ "DecRefMsg/IncRefMsg/MakeCollectable already transformed");
+ return state;
+
case Dealloc:
// Any use of -dealloc in GC is *bad*.
if (isGCEnabled()) {
@@ -3193,6 +3216,7 @@ const GRState * CFRefCount::Update(const GRState * state, SymbolRef sym,
V = V ^ RefVal::NotOwned;
// Fall-through.
case DecRef:
+ case DecRefBridgedTransfered:
switch (V.getKind()) {
default:
// case 'RefVal::Released' handled above.
@@ -3200,7 +3224,9 @@ const GRState * CFRefCount::Update(const GRState * state, SymbolRef sym,
case RefVal::Owned:
assert(V.getCount() > 0);
- if (V.getCount() == 1) V = V ^ RefVal::Released;
+ if (V.getCount() == 1)
+ V = V ^ (E == DecRefBridgedTransfered ?
+ RefVal::NotOwned : RefVal::Released);
V = V - 1;
break;
@@ -3280,15 +3306,10 @@ CFRefCount::HandleAutoreleaseCounts(const GRState * state,
std::string sbuf;
llvm::raw_string_ostream os(sbuf);
- os << "Object over-autoreleased: object was sent -autorelease";
+ os << "Object over-autoreleased: object was sent -autorelease ";
if (V.getAutoreleaseCount() > 1)
- os << V.getAutoreleaseCount() << " times";
- os << " but the object has ";
- if (V.getCount() == 0)
- os << "zero (locally visible)";
- else
- os << "+" << V.getCount();
- os << " retain counts";
+ os << V.getAutoreleaseCount() << " times ";
+ os << "but the object has a +" << V.getCount() << " retain count";
CFRefReport *report =
new CFRefReport(*static_cast<CFRefBug*>(overAutorelease),
@@ -3468,7 +3489,9 @@ void CFRefCount::ProcessNonLeakError(ExplodedNodeSet& Dst,
namespace {
class RetainReleaseChecker
- : public Checker< check::PostStmt<BlockExpr>, check::RegionChanges > {
+ : public Checker< check::PostStmt<BlockExpr>,
+ check::PostStmt<CastExpr>,
+ check::RegionChanges > {
public:
bool wantsRegionUpdate;
@@ -3476,6 +3499,9 @@ public:
void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
+
+ void checkPostStmt(const CastExpr *CE, CheckerContext &C) const;
+
const GRState *checkRegionChanges(const GRState *state,
const StoreManager::InvalidatedSymbols *invalidated,
const MemRegion * const *begin,
@@ -3545,6 +3571,48 @@ void RetainReleaseChecker::checkPostStmt(const BlockExpr *BE,
C.addTransition(state);
}
+void RetainReleaseChecker::checkPostStmt(const CastExpr *CE,
+ CheckerContext &C) const {
+ const ObjCBridgedCastExpr *BE = dyn_cast<ObjCBridgedCastExpr>(CE);
+ if (!BE)
+ return;
+
+ ArgEffect AE = IncRef;
+
+ switch (BE->getBridgeKind()) {
+ case clang::OBC_Bridge:
+ // Do nothing.
+ return;
+ case clang::OBC_BridgeRetained:
+ AE = IncRef;
+ break;
+ case clang::OBC_BridgeTransfer:
+ AE = DecRefBridgedTransfered;
+ break;
+ }
+
+ const GRState *state = C.getState();
+ SymbolRef Sym = state->getSVal(CE).getAsLocSymbol();
+ if (!Sym)
+ return;
+ const RefVal* T = state->get<RefBindings>(Sym);
+ if (!T)
+ return;
+
+ // This is gross. Once the checker and CFRefCount are unified,
+ // this will go away.
+ CFRefCount &cf = static_cast<CFRefCount&>(C.getEngine().getTF());
+ RefVal::Kind hasErr = (RefVal::Kind) 0;
+ state = cf.Update(state, Sym, *T, AE, hasErr);
+
+ if (hasErr) {
+
+ return;
+ }
+
+ C.generateNode(state);
+}
+
//===----------------------------------------------------------------------===//
// Transfer function creation for external clients.
//===----------------------------------------------------------------------===//
diff --git a/lib/StaticAnalyzer/Core/Environment.cpp b/lib/StaticAnalyzer/Core/Environment.cpp
index 48f126bfd863..3961c7b95259 100644
--- a/lib/StaticAnalyzer/Core/Environment.cpp
+++ b/lib/StaticAnalyzer/Core/Environment.cpp
@@ -83,6 +83,9 @@ SVal Environment::getSVal(const Stmt *E, SValBuilder& svalBuilder,
case Stmt::CXXBindTemporaryExprClass:
E = cast<CXXBindTemporaryExpr>(E)->getSubExpr();
continue;
+ case Stmt::MaterializeTemporaryExprClass:
+ E = cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr();
+ continue;
// Handle all other Stmt* using a lookup.
default:
break;
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index aed39eb0cec6..ffe5f0b6cdf2 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -442,7 +442,8 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
}
switch (S->getStmtClass()) {
- // C++ stuff we don't support yet.
+ // C++ and ARC stuff we don't support yet.
+ case Expr::ObjCIndirectCopyRestoreExprClass:
case Stmt::CXXBindTemporaryExprClass:
case Stmt::CXXCatchStmtClass:
case Stmt::CXXDependentScopeMemberExprClass:
@@ -478,6 +479,7 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
// We don't handle default arguments either yet, but we can fake it
// for now by just skipping them.
+ case Stmt::SubstNonTypeTemplateParmExprClass:
case Stmt::CXXDefaultArgExprClass: {
Dst.Add(Pred);
break;
@@ -508,7 +510,10 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
break;
case Stmt::GNUNullExprClass: {
- MakeNode(Dst, S, Pred, GetState(Pred)->BindExpr(S, svalBuilder.makeNull()));
+ // GNU __null is a pointer-width integer, not an actual pointer.
+ const GRState *state = GetState(Pred);
+ state = state->BindExpr(S, svalBuilder.makeIntValWithPtrWidth(0, false));
+ MakeNode(Dst, S, Pred, state);
break;
}
@@ -520,14 +525,27 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
VisitObjCPropertyRefExpr(cast<ObjCPropertyRefExpr>(S), Pred, Dst);
break;
+ case Stmt::ImplicitValueInitExprClass: {
+ const GRState *state = GetState(Pred);
+ QualType ty = cast<ImplicitValueInitExpr>(S)->getType();
+ SVal val = svalBuilder.makeZeroVal(ty);
+ MakeNode(Dst, S, Pred, state->BindExpr(S, val));
+ break;
+ }
+
+ case Stmt::ExprWithCleanupsClass: {
+ Visit(cast<ExprWithCleanups>(S)->getSubExpr(), Pred, Dst);
+ break;
+ }
+
// Cases not handled yet; but will handle some day.
case Stmt::DesignatedInitExprClass:
case Stmt::ExtVectorElementExprClass:
case Stmt::ImaginaryLiteralClass:
- case Stmt::ImplicitValueInitExprClass:
case Stmt::ObjCAtCatchStmtClass:
case Stmt::ObjCAtFinallyStmtClass:
case Stmt::ObjCAtTryStmtClass:
+ case Stmt::ObjCAutoreleasePoolStmtClass:
case Stmt::ObjCEncodeExprClass:
case Stmt::ObjCIsaExprClass:
case Stmt::ObjCProtocolExprClass:
@@ -548,7 +566,6 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
case Stmt::IntegerLiteralClass:
case Stmt::CharacterLiteralClass:
case Stmt::CXXBoolLiteralExprClass:
- case Stmt::ExprWithCleanupsClass:
case Stmt::FloatingLiteralClass:
case Stmt::SizeOfPackExprClass:
case Stmt::CXXNullPtrLiteralExprClass:
@@ -668,12 +685,35 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
case Stmt::CXXDynamicCastExprClass:
case Stmt::CXXReinterpretCastExprClass:
case Stmt::CXXConstCastExprClass:
- case Stmt::CXXFunctionalCastExprClass: {
+ case Stmt::CXXFunctionalCastExprClass:
+ case Stmt::ObjCBridgedCastExprClass: {
const CastExpr* C = cast<CastExpr>(S);
- VisitCast(C, C->getSubExpr(), Pred, Dst);
+ // Handle the previsit checks.
+ ExplodedNodeSet dstPrevisit;
+ getCheckerManager().runCheckersForPreStmt(dstPrevisit, Pred, C, *this);
+
+ // Handle the expression itself.
+ ExplodedNodeSet dstExpr;
+ for (ExplodedNodeSet::iterator i = dstPrevisit.begin(),
+ e = dstPrevisit.end(); i != e ; ++i) {
+ VisitCast(C, C->getSubExpr(), *i, dstExpr);
+ }
+
+ // Handle the postvisit checks.
+ getCheckerManager().runCheckersForPostStmt(Dst, dstExpr, C, *this);
break;
}
+ case Expr::MaterializeTemporaryExprClass: {
+ const MaterializeTemporaryExpr *Materialize
+ = cast<MaterializeTemporaryExpr>(S);
+ if (!Materialize->getType()->isRecordType())
+ CreateCXXTemporaryObject(Materialize->GetTemporaryExpr(), Pred, Dst);
+ else
+ Visit(Materialize->GetTemporaryExpr(), Pred, Dst);
+ break;
+ }
+
case Stmt::InitListExprClass:
VisitInitListExpr(cast<InitListExpr>(S), Pred, Dst);
break;
@@ -2148,10 +2188,19 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
Pred = *I;
switch (CastE->getCastKind()) {
+ case CK_LValueToRValue:
+ assert(false && "LValueToRValue casts handled earlier.");
+ case CK_GetObjCProperty:
+ assert(false && "GetObjCProperty casts handled earlier.");
case CK_ToVoid:
Dst.Add(Pred);
continue;
- case CK_LValueToRValue:
+ // The analyzer doesn't do anything special with these casts,
+ // since it understands retain/release semantics already.
+ case CK_ObjCProduceObject:
+ case CK_ObjCConsumeObject:
+ case CK_ObjCReclaimReturnedObject: // Fall-through.
+ // True no-ops.
case CK_NoOp:
case CK_FunctionToPointerDecay: {
// Copy the SVal of Ex to CastE.
@@ -2161,7 +2210,6 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
MakeNode(Dst, CastE, Pred, state);
continue;
}
- case CK_GetObjCProperty:
case CK_Dependent:
case CK_ArrayToPointerDecay:
case CK_BitCast:
@@ -2273,17 +2321,9 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
// time a function is called those values may not be current.
ExplodedNodeSet Tmp;
- if (InitEx) {
- if (VD->getType()->isReferenceType() && !InitEx->isLValue()) {
- // If the initializer is C++ record type, it should already has a
- // temp object.
- if (!InitEx->getType()->isRecordType())
- CreateCXXTemporaryObject(InitEx, Pred, Tmp);
- else
- Tmp.Add(Pred);
- } else
- Visit(InitEx, Pred, Tmp);
- } else
+ if (InitEx)
+ Visit(InitEx, Pred, Tmp);
+ else
Tmp.Add(Pred);
ExplodedNodeSet Tmp2;
diff --git a/lib/StaticAnalyzer/Core/RegionStore.cpp b/lib/StaticAnalyzer/Core/RegionStore.cpp
index d0d8f601f071..23dd6416a8f1 100644
--- a/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -1377,7 +1377,12 @@ StoreRef RegionStoreManager::setImplicitDefaultValue(Store store,
V = svalBuilder.makeZeroVal(Ctx.IntTy);
}
else {
- return StoreRef(store, *this);
+ // We can't represent values of this type, but we still need to set a value
+ // to record that the region has been initialized.
+ // If this assertion ever fires, a new case should be added above -- we
+ // should know how to default-initialize any value we can symbolicate.
+ assert(!SymbolManager::canSymbolicate(T) && "This type is representable");
+ V = UnknownVal();
}
return StoreRef(addBinding(B, R, BindingKey::Default,
diff --git a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
index 197442b1574f..80c18a335fde 100644
--- a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
+++ b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
@@ -415,6 +415,24 @@ SVal SimpleSValBuilder::evalBinOpNN(const GRState *state,
case nonloc::ConcreteIntKind: {
const nonloc::ConcreteInt& lhsInt = cast<nonloc::ConcreteInt>(lhs);
+ // Is the RHS a symbol we can simplify?
+ // FIXME: This was mostly copy/pasted from the LHS-is-a-symbol case.
+ if (const nonloc::SymbolVal *srhs = dyn_cast<nonloc::SymbolVal>(&rhs)) {
+ SymbolRef RSym = srhs->getSymbol();
+ if (RSym->getType(Context)->isIntegerType()) {
+ if (const llvm::APSInt *Constant = state->getSymVal(RSym)) {
+ // The symbol evaluates to a constant.
+ const llvm::APSInt *rhs_I;
+ if (BinaryOperator::isRelationalOp(op))
+ rhs_I = &BasicVals.Convert(lhsInt.getValue(), *Constant);
+ else
+ rhs_I = &BasicVals.Convert(resultTy, *Constant);
+
+ rhs = nonloc::ConcreteInt(*rhs_I);
+ }
+ }
+ }
+
if (isa<nonloc::ConcreteInt>(rhs)) {
return lhsInt.evalBinOp(*this, op, cast<nonloc::ConcreteInt>(rhs));
} else {
@@ -461,13 +479,22 @@ SVal SimpleSValBuilder::evalBinOpNN(const GRState *state,
case nonloc::SymbolValKind: {
nonloc::SymbolVal *slhs = cast<nonloc::SymbolVal>(&lhs);
SymbolRef Sym = slhs->getSymbol();
+ QualType lhsType = Sym->getType(Context);
+
+ // The conversion type is usually the result type, but not in the case
+ // of relational expressions.
+ QualType conversionType = resultTy;
+ if (BinaryOperator::isRelationalOp(op))
+ conversionType = lhsType;
+
// Does the symbol simplify to a constant? If so, "fold" the constant
// by setting 'lhs' to a ConcreteInt and try again.
- if (Sym->getType(Context)->isIntegerType())
+ if (lhsType->isIntegerType())
if (const llvm::APSInt *Constant = state->getSymVal(Sym)) {
// The symbol evaluates to a constant. If necessary, promote the
// folded constant (LHS) to the result type.
- const llvm::APSInt &lhs_I = BasicVals.Convert(resultTy, *Constant);
+ const llvm::APSInt &lhs_I = BasicVals.Convert(conversionType,
+ *Constant);
lhs = nonloc::ConcreteInt(lhs_I);
// Also promote the RHS (if necessary).
@@ -479,7 +506,7 @@ SVal SimpleSValBuilder::evalBinOpNN(const GRState *state,
// Other operators: do an implicit conversion. This shouldn't be
// necessary once we support truncation/extension of symbolic values.
if (nonloc::ConcreteInt *rhs_I = dyn_cast<nonloc::ConcreteInt>(&rhs)){
- rhs = nonloc::ConcreteInt(BasicVals.Convert(resultTy,
+ rhs = nonloc::ConcreteInt(BasicVals.Convert(conversionType,
rhs_I->getValue()));
}
@@ -492,7 +519,8 @@ SVal SimpleSValBuilder::evalBinOpNN(const GRState *state,
if (RSym->getType(Context)->isIntegerType()) {
if (const llvm::APSInt *Constant = state->getSymVal(RSym)) {
// The symbol evaluates to a constant.
- const llvm::APSInt &rhs_I = BasicVals.Convert(resultTy, *Constant);
+ const llvm::APSInt &rhs_I = BasicVals.Convert(conversionType,
+ *Constant);
rhs = nonloc::ConcreteInt(rhs_I);
}
}
diff --git a/runtime/compiler-rt/Makefile b/runtime/compiler-rt/Makefile
index dcdd4f5ec03f..0d770db17c47 100644
--- a/runtime/compiler-rt/Makefile
+++ b/runtime/compiler-rt/Makefile
@@ -42,7 +42,7 @@ ifeq ($(shell test -d $(COMPILERRT_SRC_ROOT) && echo OK),OK)
RuntimeDirs :=
ifeq ($(OS),Darwin)
RuntimeDirs += darwin
-RuntimeLibrary.darwin.Configs = eprintf 10.4 ios cc_kext
+RuntimeLibrary.darwin.Configs = eprintf 10.4 osx ios cc_kext
# On Darwin, fake Clang into using the iOS assembler (since compiler-rt wants to
# build ARM bits).
diff --git a/test/ARCMT/Common.h b/test/ARCMT/Common.h
new file mode 100644
index 000000000000..c57f3e75e49e
--- /dev/null
+++ b/test/ARCMT/Common.h
@@ -0,0 +1,55 @@
+#if __has_feature(objc_arr)
+#define NS_AUTOMATED_REFCOUNT_UNAVAILABLE __attribute__((unavailable("not available in automatic reference counting mode")))
+#else
+#define NS_AUTOMATED_REFCOUNT_UNAVAILABLE
+#endif
+
+typedef int BOOL;
+typedef unsigned NSUInteger;
+typedef int int32_t;
+typedef unsigned char uint8_t;
+typedef int32_t UChar32;
+typedef unsigned char UChar;
+
+@protocol NSObject
+- (BOOL)isEqual:(id)object;
+- (id)retain NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
+- (NSUInteger)retainCount NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
+- (oneway void)release NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
+- (id)autorelease NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
+@end
+
+@interface NSObject <NSObject> {}
+- (id)init;
+
++ (id)new;
++ (id)alloc;
+- (void)dealloc;
+
+- (void)finalize;
+
+- (id)copy;
+- (id)mutableCopy;
+@end
+
+NS_AUTOMATED_REFCOUNT_UNAVAILABLE
+@interface NSAutoreleasePool : NSObject {
+@private
+ void *_token;
+ void *_reserved3;
+ void *_reserved2;
+ void *_reserved;
+}
+
++ (void)addObject:(id)anObject;
+
+- (void)addObject:(id)anObject;
+
+- (void)drain;
+
+@end
+
+typedef const void* objc_objectptr_t;
+extern __attribute__((ns_returns_retained)) id objc_retainedObject(objc_objectptr_t __attribute__((cf_consumed)) pointer);
+extern __attribute__((ns_returns_not_retained)) id objc_unretainedObject(objc_objectptr_t pointer);
+extern objc_objectptr_t objc_unretainedPointer(id object);
diff --git a/test/ARCMT/Inputs/test.h b/test/ARCMT/Inputs/test.h
new file mode 100644
index 000000000000..756295f27e69
--- /dev/null
+++ b/test/ARCMT/Inputs/test.h
@@ -0,0 +1,15 @@
+@protocol NSObject
+- (oneway void)release;
+@end
+
+#ifdef PART1
+static inline void part1(id p) {
+ [p release];
+}
+#endif
+
+#ifdef PART2
+static inline void part2(id p) {
+ [p release];
+}
+#endif
diff --git a/test/ARCMT/Inputs/test.h.result b/test/ARCMT/Inputs/test.h.result
new file mode 100644
index 000000000000..0638a3378c1c
--- /dev/null
+++ b/test/ARCMT/Inputs/test.h.result
@@ -0,0 +1,13 @@
+@protocol NSObject
+- (oneway void)release;
+@end
+
+#ifdef PART1
+static inline void part1(id p) {
+}
+#endif
+
+#ifdef PART2
+static inline void part2(id p) {
+}
+#endif
diff --git a/test/ARCMT/Inputs/test1.m.in b/test/ARCMT/Inputs/test1.m.in
new file mode 100644
index 000000000000..8416a8896569
--- /dev/null
+++ b/test/ARCMT/Inputs/test1.m.in
@@ -0,0 +1,6 @@
+#define PART1
+#include "test.h"
+
+void test1(id p) {
+ [p release];
+}
diff --git a/test/ARCMT/Inputs/test1.m.in.result b/test/ARCMT/Inputs/test1.m.in.result
new file mode 100644
index 000000000000..f351fe6c8355
--- /dev/null
+++ b/test/ARCMT/Inputs/test1.m.in.result
@@ -0,0 +1,5 @@
+#define PART1
+#include "test.h"
+
+void test1(id p) {
+}
diff --git a/test/ARCMT/Inputs/test2.m.in b/test/ARCMT/Inputs/test2.m.in
new file mode 100644
index 000000000000..99f87b072171
--- /dev/null
+++ b/test/ARCMT/Inputs/test2.m.in
@@ -0,0 +1,6 @@
+#define PART2
+#include "test.h"
+
+void test2(id p) {
+ [p release];
+}
diff --git a/test/ARCMT/Inputs/test2.m.in.result b/test/ARCMT/Inputs/test2.m.in.result
new file mode 100644
index 000000000000..f8e918ce2598
--- /dev/null
+++ b/test/ARCMT/Inputs/test2.m.in.result
@@ -0,0 +1,5 @@
+#define PART2
+#include "test.h"
+
+void test2(id p) {
+}
diff --git a/test/ARCMT/assign-prop-no-arc-runtime.m b/test/ARCMT/assign-prop-no-arc-runtime.m
new file mode 100644
index 000000000000..0baa1d28ff56
--- /dev/null
+++ b/test/ARCMT/assign-prop-no-arc-runtime.m
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-macosx10.6 -fobjc-nonfragile-abi -fsyntax-only %s > %t
+// RUN: diff %t %s.result
+
+#include "Common.h"
+
+@interface Foo : NSObject {
+ NSObject *x;
+}
+@property (readonly,assign) id x;
+@end
+
+@implementation Foo
+@synthesize x;
+@end
diff --git a/test/ARCMT/assign-prop-no-arc-runtime.m.result b/test/ARCMT/assign-prop-no-arc-runtime.m.result
new file mode 100644
index 000000000000..49e91d83cfec
--- /dev/null
+++ b/test/ARCMT/assign-prop-no-arc-runtime.m.result
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-macosx10.6 -fobjc-nonfragile-abi -fsyntax-only %s > %t
+// RUN: diff %t %s.result
+
+#include "Common.h"
+
+@interface Foo : NSObject {
+ NSObject *__unsafe_unretained x;
+}
+@property (readonly,unsafe_unretained) id x;
+@end
+
+@implementation Foo
+@synthesize x;
+@end
diff --git a/test/ARCMT/assign-prop-with-arc-runtime.m b/test/ARCMT/assign-prop-with-arc-runtime.m
new file mode 100644
index 000000000000..4e4ae774a25c
--- /dev/null
+++ b/test/ARCMT/assign-prop-with-arc-runtime.m
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -fobjc-runtime-has-weak -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-macosx10.7 -fobjc-nonfragile-abi -fsyntax-only %s > %t
+// RUN: diff %t %s.result
+
+#include "Common.h"
+
+__attribute__((objc_arc_weak_reference_unavailable))
+@interface WeakOptOut
+@end
+
+@class _NSCachedAttributedString;
+typedef _NSCachedAttributedString *BadClassForWeak;
+
+@class Forw;
+
+@interface Foo : NSObject {
+ Foo *x, *w, *q1, *q2;
+ WeakOptOut *oo;
+ BadClassForWeak bcw;
+ id not_safe1;
+ NSObject *not_safe2;
+ Forw *not_safe3;
+}
+@property (readonly,assign) Foo *x;
+@property (assign) Foo *w;
+@property Foo *q1, *q2;
+@property (assign) WeakOptOut *oo;
+@property (assign) BadClassForWeak bcw;
+@property (assign) id not_safe1;
+@property () NSObject *not_safe2;
+@property Forw *not_safe3;
+
+@property (assign) Foo *no_user_ivar1;
+@property (readonly) Foo *no_user_ivar2;
+@end
+
+@implementation Foo
+@synthesize x,w,q1,q2,oo,bcw,not_safe1,not_safe2,not_safe3;
+@synthesize no_user_ivar1, no_user_ivar2;
+@end
diff --git a/test/ARCMT/assign-prop-with-arc-runtime.m.result b/test/ARCMT/assign-prop-with-arc-runtime.m.result
new file mode 100644
index 000000000000..eb34c168e406
--- /dev/null
+++ b/test/ARCMT/assign-prop-with-arc-runtime.m.result
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -fobjc-runtime-has-weak -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-macosx10.7 -fobjc-nonfragile-abi -fsyntax-only %s > %t
+// RUN: diff %t %s.result
+
+#include "Common.h"
+
+__attribute__((objc_arc_weak_reference_unavailable))
+@interface WeakOptOut
+@end
+
+@class _NSCachedAttributedString;
+typedef _NSCachedAttributedString *BadClassForWeak;
+
+@class Forw;
+
+@interface Foo : NSObject {
+ Foo *__weak x, *__weak w, *__weak q1, *__weak q2;
+ WeakOptOut *__unsafe_unretained oo;
+ BadClassForWeak __unsafe_unretained bcw;
+ id __unsafe_unretained not_safe1;
+ NSObject *__unsafe_unretained not_safe2;
+ Forw *__unsafe_unretained not_safe3;
+}
+@property (readonly,weak) Foo *x;
+@property (weak) Foo *w;
+@property (weak) Foo *q1, *q2;
+@property (unsafe_unretained) WeakOptOut *oo;
+@property (unsafe_unretained) BadClassForWeak bcw;
+@property (unsafe_unretained) id not_safe1;
+@property (unsafe_unretained) NSObject *not_safe2;
+@property (unsafe_unretained) Forw *not_safe3;
+
+@property (weak) Foo *no_user_ivar1;
+@property (weak, readonly) Foo *no_user_ivar2;
+@end
+
+@implementation Foo
+@synthesize x,w,q1,q2,oo,bcw,not_safe1,not_safe2,not_safe3;
+@synthesize no_user_ivar1, no_user_ivar2;
+@end
diff --git a/test/ARCMT/atautorelease-2.m b/test/ARCMT/atautorelease-2.m
new file mode 100644
index 000000000000..5d2977227781
--- /dev/null
+++ b/test/ARCMT/atautorelease-2.m
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// RUN: diff %t %s.result
+
+@interface NSAutoreleasePool
+- drain;
++new;
++alloc;
+-init;
+-autorelease;
+-release;
+@end
+
+void NSLog(id, ...);
+
+int main (int argc, const char * argv[]) {
+ NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+ NSAutoreleasePool *chunkPool = [[NSAutoreleasePool alloc] init];
+
+ while (argc) {
+ [chunkPool release];
+ return 0;
+ }
+
+ [chunkPool drain];
+ [pool drain];
+
+ return 0;
+}
diff --git a/test/ARCMT/atautorelease-2.m.result b/test/ARCMT/atautorelease-2.m.result
new file mode 100644
index 000000000000..7bb164723e19
--- /dev/null
+++ b/test/ARCMT/atautorelease-2.m.result
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// RUN: diff %t %s.result
+
+@interface NSAutoreleasePool
+- drain;
++new;
++alloc;
+-init;
+-autorelease;
+-release;
+@end
+
+void NSLog(id, ...);
+
+int main (int argc, const char * argv[]) {
+ @autoreleasepool {
+ @autoreleasepool {
+
+ while (argc) {
+ return 0;
+ }
+
+ }
+ }
+
+ return 0;
+}
diff --git a/test/ARCMT/atautorelease-3.m b/test/ARCMT/atautorelease-3.m
new file mode 100644
index 000000000000..5d71c33b6bc8
--- /dev/null
+++ b/test/ARCMT/atautorelease-3.m
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// RUN: diff %t %s.result
+
+@interface NSAutoreleasePool
+- drain;
++new;
++alloc;
+-init;
+-autorelease;
+- release;
+@end
+
+void NSLog(id, ...);
+
+void test1(int x) {
+ // All this stuff get removed since nothing is happening inside.
+ NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+ NSAutoreleasePool *chunkPool = [[NSAutoreleasePool alloc] init];
+ while (x) {
+ chunkPool = [[NSAutoreleasePool alloc] init];
+ [chunkPool release];
+ }
+
+ [chunkPool drain];
+ [pool drain];
+}
+
+void test2(int x) {
+ NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+ NSAutoreleasePool *chunkPool = [[NSAutoreleasePool alloc] init];
+ while (x) {
+ chunkPool = [[NSAutoreleasePool alloc] init];
+ ++x;
+ [chunkPool release];
+ }
+
+ [chunkPool drain];
+ [pool drain];
+}
diff --git a/test/ARCMT/atautorelease-3.m.result b/test/ARCMT/atautorelease-3.m.result
new file mode 100644
index 000000000000..682118e82f28
--- /dev/null
+++ b/test/ARCMT/atautorelease-3.m.result
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// RUN: diff %t %s.result
+
+@interface NSAutoreleasePool
+- drain;
++new;
++alloc;
+-init;
+-autorelease;
+- release;
+@end
+
+void NSLog(id, ...);
+
+void test1(int x) {
+ // All this stuff get removed since nothing is happening inside.
+}
+
+void test2(int x) {
+ @autoreleasepool {
+ @autoreleasepool {
+ while (x) {
+ @autoreleasepool {
+ ++x;
+ }
+ }
+
+ }
+ }
+}
diff --git a/test/ARCMT/atautorelease-check.m b/test/ARCMT/atautorelease-check.m
new file mode 100644
index 000000000000..6528f3e62d1e
--- /dev/null
+++ b/test/ARCMT/atautorelease-check.m
@@ -0,0 +1,144 @@
+// RUN: %clang_cc1 -arcmt-check -verify -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi %s
+
+#if __has_feature(objc_arr)
+#define NS_AUTOMATED_REFCOUNT_UNAVAILABLE __attribute__((unavailable("not available in automatic reference counting mode")))
+#else
+#define NS_AUTOMATED_REFCOUNT_UNAVAILABLE
+#endif
+
+typedef struct _NSZone NSZone;
+typedef int BOOL;
+typedef unsigned NSUInteger;
+
+@protocol NSObject
+- (BOOL)isEqual:(id)object;
+- (id)retain NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
+- (NSUInteger)retainCount NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
+- (oneway void)release NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
+- (id)autorelease NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
+
+- (NSZone *)zone NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
+@end
+
+@protocol NSCopying
+- (id)copyWithZone:(NSZone *)zone;
+@end
+
+@protocol NSMutableCopying
+- (id)mutableCopyWithZone:(NSZone *)zone;
+@end
+
+@interface NSObject <NSObject> {}
+- (id)init;
+
++ (id)new;
++ (id)allocWithZone:(NSZone *)zone NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
++ (id)alloc;
+- (void)dealloc;
+
+- (void)finalize;
+
+- (id)copy;
+- (id)mutableCopy;
+
++ (id)copyWithZone:(NSZone *)zone NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
++ (id)mutableCopyWithZone:(NSZone *)zone NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
+@end
+
+extern void NSRecycleZone(NSZone *zone);
+
+NS_AUTOMATED_REFCOUNT_UNAVAILABLE
+@interface NSAutoreleasePool : NSObject { // expected-note 13 {{marked unavailable here}}
+@private
+ void *_token;
+ void *_reserved3;
+ void *_reserved2;
+ void *_reserved;
+}
+
++ (void)addObject:(id)anObject;
+
+- (void)addObject:(id)anObject;
+
+- (void)drain;
+
+@end
+
+
+void NSLog(id, ...);
+
+int main (int argc, const char * argv[]) {
+ NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+ NSAutoreleasePool *chunkPool = [[NSAutoreleasePool alloc] init]; // expected-error 2 {{'NSAutoreleasePool' is unavailable}}
+
+ while (argc) {
+ [chunkPool release];
+ // the following pool was not released in this scope, don't touch it.
+ chunkPool = [[NSAutoreleasePool alloc] init]; // expected-error {{'NSAutoreleasePool' is unavailable}}
+ }
+
+ [chunkPool drain];
+ [pool drain];
+
+ return 0;
+}
+
+void f(void) {
+ NSAutoreleasePool * pool; // expected-error {{'NSAutoreleasePool' is unavailable}}
+
+ for (int i=0; i != 10; ++i) {
+ id x = pool; // We won't touch a NSAutoreleasePool if we can't safely
+ // remove all the references to it.
+ }
+
+ pool = [[NSAutoreleasePool alloc] init]; // expected-error {{'NSAutoreleasePool' is unavailable}}
+ NSLog(@"%s", "YES");
+ [pool release];
+}
+
+void f2(void) {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // expected-error 2 {{'NSAutoreleasePool' is unavailable}} \
+ // expected-note {{scope begins here}}
+
+ // 'x' is declared inside the "pool scope" but used outside it, if we create
+ // a @autorelease scope it will be undefined outside it so don't touch the pool.
+ int x = 0; // expected-note {{declared here}}
+
+ [pool release]; // expected-note {{scope ends here}}
+
+ ++x; // expected-error {{a name is referenced outside the NSAutoreleasePool scope that it was declared in}}
+}
+
+void f3(void) {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // expected-error 2 {{'NSAutoreleasePool' is unavailable}} \
+ // expected-note {{scope begins here}}
+
+ struct S { int x; }; // expected-note {{declared here}}
+
+ [pool release]; // expected-note {{scope ends here}}
+
+ struct S *var; // expected-error {{a name is referenced outside the NSAutoreleasePool scope that it was declared in}}
+ var->x = 0;
+}
+
+void f4(void) {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // expected-error 2 {{'NSAutoreleasePool' is unavailable}} \
+ // expected-note {{scope begins here}}
+
+ enum { Bar }; // expected-note {{declared here}}
+
+ [pool release]; // expected-note {{scope ends here}}
+
+ int x = Bar; // expected-error {{a name is referenced outside the NSAutoreleasePool scope that it was declared in}}
+}
+
+void f5(void) {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // expected-error 2 {{'NSAutoreleasePool' is unavailable}} \
+ // expected-note {{scope begins here}}
+
+ typedef int Bar; // expected-note {{declared here}}
+
+ [pool release]; // expected-note {{scope ends here}}
+
+ Bar x; // expected-error {{a name is referenced outside the NSAutoreleasePool scope that it was declared in}}
+}
diff --git a/test/ARCMT/atautorelease.m b/test/ARCMT/atautorelease.m
new file mode 100644
index 000000000000..bdf77197a8a5
--- /dev/null
+++ b/test/ARCMT/atautorelease.m
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// RUN: diff %t %s.result
+
+#include "Common.h"
+
+void NSLog(id, ...);
+
+int main (int argc, const char * argv[]) {
+
+ NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+
+ if (argc) {
+ NSAutoreleasePool * pool = [NSAutoreleasePool new];
+ NSLog(@"%s", "YES");
+ [pool drain];
+ }
+ [pool drain];
+
+ NSAutoreleasePool * pool1 = [[NSAutoreleasePool alloc] init];
+ NSLog(@"%s", "YES");
+ [pool1 release];
+
+ return 0;
+}
+
+void f(void) {
+ NSAutoreleasePool *pool1;
+
+ pool1 = [NSAutoreleasePool new];
+ int x = 4;
+
+ NSAutoreleasePool *pool2 = [[NSAutoreleasePool alloc] init];
+ ++x;
+ [pool2 drain];
+
+ [pool1 release];
+}
+
+int UIApplicationMain(int argc, char *argv[]);
+
+int main2(int argc, char *argv[]) {
+ NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+ int result = UIApplicationMain(argc, argv);
+ [pool release];
+ return result;
+}
diff --git a/test/ARCMT/atautorelease.m.result b/test/ARCMT/atautorelease.m.result
new file mode 100644
index 000000000000..ccce1bd87570
--- /dev/null
+++ b/test/ARCMT/atautorelease.m.result
@@ -0,0 +1,46 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// RUN: diff %t %s.result
+
+#include "Common.h"
+
+void NSLog(id, ...);
+
+int main (int argc, const char * argv[]) {
+
+ @autoreleasepool {
+
+ if (argc) {
+ @autoreleasepool {
+ NSLog(@"%s", "YES");
+ }
+ }
+ }
+
+ @autoreleasepool {
+ NSLog(@"%s", "YES");
+ }
+
+ return 0;
+}
+
+void f(void) {
+
+ @autoreleasepool {
+ int x = 4;
+
+ @autoreleasepool {
+ ++x;
+ }
+
+ }
+}
+
+int UIApplicationMain(int argc, char *argv[]);
+
+int main2(int argc, char *argv[]) {
+ @autoreleasepool {
+ int result = UIApplicationMain(argc, argv);
+ return result;
+ }
+}
diff --git a/test/ARCMT/autoreleases.m b/test/ARCMT/autoreleases.m
new file mode 100644
index 000000000000..a12db8178f7a
--- /dev/null
+++ b/test/ARCMT/autoreleases.m
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// RUN: diff %t %s.result
+
+typedef unsigned char BOOL;
+
+@interface NSObject {
+ id isa;
+}
++new;
++alloc;
+-init;
+-autorelease;
+@end
+
+@interface NSAutoreleasePool : NSObject
+- drain;
+@end
+
+@interface A : NSObject {
+@package
+ id object;
+}
+@end
+
+@interface B : NSObject
+- (BOOL)containsSelf:(A*)a;
+@end
+
+@implementation A
+@end
+
+@implementation B
+- (BOOL)containsSelf:(A*)a {
+ return a->object == self;
+}
+@end
+
+void NSLog(id, ...);
+
+int main (int argc, const char * argv[]) {
+ NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+ A *a = [[A new] autorelease];
+ B *b = [[B new] autorelease];
+ NSLog(@"%s", [b containsSelf:a] ? "YES" : "NO");
+ [pool drain];
+ return 0;
+}
diff --git a/test/ARCMT/autoreleases.m.result b/test/ARCMT/autoreleases.m.result
new file mode 100644
index 000000000000..796bfbb9d659
--- /dev/null
+++ b/test/ARCMT/autoreleases.m.result
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// RUN: diff %t %s.result
+
+typedef unsigned char BOOL;
+
+@interface NSObject {
+ id isa;
+}
++new;
++alloc;
+-init;
+-autorelease;
+@end
+
+@interface NSAutoreleasePool : NSObject
+- drain;
+@end
+
+@interface A : NSObject {
+@package
+ id object;
+}
+@end
+
+@interface B : NSObject
+- (BOOL)containsSelf:(A*)a;
+@end
+
+@implementation A
+@end
+
+@implementation B
+- (BOOL)containsSelf:(A*)a {
+ return a->object == self;
+}
+@end
+
+void NSLog(id, ...);
+
+int main (int argc, const char * argv[]) {
+ @autoreleasepool {
+ A *a = [A new];
+ B *b = [B new];
+ NSLog(@"%s", [b containsSelf:a] ? "YES" : "NO");
+ }
+ return 0;
+}
diff --git a/test/ARCMT/checking.m b/test/ARCMT/checking.m
new file mode 100644
index 000000000000..eea7a9f2547c
--- /dev/null
+++ b/test/ARCMT/checking.m
@@ -0,0 +1,295 @@
+// RUN: %clang_cc1 -arcmt-check -verify -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi %s
+
+#include "Common.h"
+
+typedef const struct __CFString * CFStringRef;
+extern const CFStringRef kUTTypePlainText;
+extern const CFStringRef kUTTypeRTF;
+@class NSString;
+@class A;
+
+struct UnsafeS {
+ A *__unsafe_unretained unsafeObj;
+};
+
+@interface A : NSObject
+- (id)retain;
+- (id)retainCount;
+- (id)autorelease;
+- (id)init;
+- (oneway void)release;
+- (void)dealloc;
+-(void)test;
+-(id)delegate;
+@end
+
+@implementation A
+-(void)test {
+ [super dealloc];
+}
+-(void)dealloc {
+ [super dealloc];
+}
+
+- (id)retain { return self; } // expected-error {{ARC forbids implementation}}
+- (id)retainCount { return self; } // expected-error {{ARC forbids implementation}}
+- (id)autorelease { return self; } // expected-error {{ARC forbids implementation}}
+- (oneway void)release { } // expected-error {{ARC forbids implementation}}
+
+-(id)delegate { return self; }
+@end
+
+id global_foo;
+
+void test1(A *a, BOOL b, struct UnsafeS *unsafeS) {
+ [[a delegate] release]; // expected-error {{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}} \
+ // expected-error {{ARC forbids explicit message send}}
+ [a.delegate release]; // expected-error {{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}} \
+ // expected-error {{ARC forbids explicit message send}}
+ [unsafeS->unsafeObj retain]; // expected-error {{it is not safe to remove 'retain' message on an __unsafe_unretained type}} \
+ // expected-error {{ARC forbids explicit message send}}
+ id foo = [unsafeS->unsafeObj retain]; // no warning.
+ [global_foo retain]; // expected-error {{it is not safe to remove 'retain' message on a global variable}} \
+ // expected-error {{ARC forbids explicit message send}}
+ [global_foo release]; // expected-error {{it is not safe to remove 'release' message on a global variable}} \
+ // expected-error {{ARC forbids explicit message send}}
+ [a dealloc];
+ [a retain];
+ [a retainCount]; // expected-error {{ARC forbids explicit message send of 'retainCount'}}
+ [a release];
+ [a autorelease]; // expected-error {{it is not safe to remove an unused 'autorelease' message; its receiver may be destroyed immediately}} \
+ // expected-error {{ARC forbids explicit message send}}
+
+ CFStringRef cfstr;
+ NSString *str = (NSString *)cfstr; // expected-error {{cast of C pointer type 'CFStringRef' (aka 'const struct __CFString *') to Objective-C pointer type 'NSString *' requires a bridged cast}} \
+ // expected-note{{use __bridge to convert directly (no change in ownership)}} \
+ // expected-note{{use __bridge_transfer to transfer ownership of a +1 'CFStringRef' (aka 'const struct __CFString *') into ARC}}
+ str = (NSString *)kUTTypePlainText;
+ str = b ? kUTTypeRTF : kUTTypePlainText;
+ str = (NSString *)(b ? kUTTypeRTF : kUTTypePlainText);
+ str = (NSString *)a; // no change.
+
+ SEL s = @selector(retain); // expected-error {{ARC forbids use of 'retain' in a @selector}}
+ s = @selector(release); // expected-error {{ARC forbids use of 'release' in a @selector}}
+ s = @selector(autorelease); // expected-error {{ARC forbids use of 'autorelease' in a @selector}}
+ s = @selector(dealloc); // expected-error {{ARC forbids use of 'dealloc' in a @selector}}
+
+ static id __autoreleasing X1; // expected-error {{global variables cannot have __autoreleasing ownership}}
+}
+
+struct S {
+ A* a; // expected-error {{ARC forbids Objective-C objects in structs or unions}}
+};
+
+@interface B
+-(id)alloc;
+- (id)initWithInt: (int) i;
+@end
+
+void rdar8861761() {
+ B *o1 = [[B alloc] initWithInt:0];
+ B *o2 = [B alloc];
+ [o2 initWithInt:0];
+}
+
+@interface Test13
+- (id) init0;
+- (void) noninit;
+@end
+@implementation Test13
+- (id) init0 {
+ self = 0;
+}
+- (void) noninit {
+ self = 0; // expected-error {{cannot assign to 'self' outside of a method in the init family}}
+
+ for (id x in collection) { // expected-error {{use of undeclared identifier 'collection'}}
+ x = 0;
+ }
+}
+@end
+
+void * cvt(id arg)
+{
+ void* voidp_val;
+ (void)(int*)arg; // expected-error {{disallowed}}
+ (void)(id)arg;
+ (void)(__autoreleasing id*)arg; // expected-error {{disallowed}}
+ (void)(id*)arg; // expected-error {{disallowed}}
+
+ (void)(__autoreleasing id**)voidp_val;
+ (void)(void*)voidp_val;
+ (void)(void**)arg; // expected-error {{disallowed}}
+ cvt((void*)arg); // expected-error {{requires a bridged cast}} expected-error {{disallowed}} \
+ // expected-note {{use __bridge}} expected-note {{use __bridge_retained}}
+ cvt(0);
+ (void)(__strong id**)(0);
+ return arg; // expected-error {{disallowed}}
+}
+
+
+void test12(id collection) {
+ for (id x in collection) {
+ x = 0;
+ }
+
+ for (__strong id x in collection) {
+ x = 0;
+ }
+}
+
+void test6(unsigned cond) {
+ // FIXME: Fix this automatically ?
+ switch (cond) {
+ case 0:
+ ;
+ id x; // expected-note {{jump bypasses initialization of retaining variable}}
+
+ case 1: // expected-error {{switch case is in protected scope}}
+ break;
+ }
+}
+
+@class Test8_incomplete;
+@interface Test8_complete @end;
+@interface Test8_super @end;
+@interface Test8 : Test8_super
+- (id) init00;
+- (id) init01; // expected-note {{declaration in interface}}
+- (id) init02;
+- (id) init03; // covariance
+- (id) init04; // covariance
+- (id) init05;
+
+- (void) init10; // expected-note {{declaration in interface is not in the 'init' family because its result type is not an object pointer}}
+- (void) init11;
+- (void) init12;
+- (void) init13; // expected-note {{declaration in interface is not in the 'init' family because its result type is not an object pointer}}
+- (void) init14; // expected-note {{declaration in interface is not in the 'init' family because its result type is not an object pointer}}
+- (void) init15;
+
+// These should be invalid to actually call.
+- (Test8_incomplete*) init20;
+- (Test8_incomplete*) init21; // expected-note {{declaration in interface}}
+- (Test8_incomplete*) init22;
+- (Test8_incomplete*) init23;
+- (Test8_incomplete*) init24;
+- (Test8_incomplete*) init25;
+
+- (Test8_super*) init30; // id exception to covariance
+- (Test8_super*) init31; // expected-note {{declaration in interface}}
+- (Test8_super*) init32;
+- (Test8_super*) init33;
+- (Test8_super*) init34; // covariance
+- (Test8_super*) init35;
+
+- (Test8*) init40; // id exception to covariance
+- (Test8*) init41; // expected-note {{declaration in interface}}
+- (Test8*) init42;
+- (Test8*) init43; // this should be a warning, but that's a general language thing, not an ARC thing
+- (Test8*) init44;
+- (Test8*) init45;
+
+- (Test8_complete*) init50; // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_complete*) init51; // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_complete*) init52; // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_complete*) init53; // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_complete*) init54; // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_complete*) init55; // expected-error {{init methods must return a type related to the receiver type}}
+@end
+@implementation Test8
+- (id) init00 { return 0; }
+- (id) init10 { return 0; } // expected-error {{method implementation does not match its declaration}}
+- (id) init20 { return 0; }
+- (id) init30 { return 0; }
+- (id) init40 { return 0; }
+- (id) init50 { return 0; }
+
+- (void) init01 {} // expected-error {{method was declared as an 'init' method, but its implementation doesn't match because its result type is not an object pointer}}
+- (void) init11 {}
+- (void) init21 {} // expected-error {{method was declared as an 'init' method, but its implementation doesn't match because its result type is not an object pointer}}
+- (void) init31 {} // expected-error {{method was declared as an 'init' method, but its implementation doesn't match because its result type is not an object pointer}}
+- (void) init41 {} // expected-error {{method was declared as an 'init' method, but its implementation doesn't match because its result type is not an object pointer}}
+- (void) init51 {}
+
+- (Test8_incomplete*) init02 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_incomplete*) init12 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_incomplete*) init22 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_incomplete*) init32 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_incomplete*) init42 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_incomplete*) init52 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
+
+- (Test8_super*) init03 { return 0; }
+- (Test8_super*) init13 { return 0; } // expected-error {{method implementation does not match its declaration}}
+- (Test8_super*) init23 { return 0; }
+- (Test8_super*) init33 { return 0; }
+- (Test8_super*) init43 { return 0; }
+- (Test8_super*) init53 { return 0; }
+
+- (Test8*) init04 { return 0; }
+- (Test8*) init14 { return 0; } // expected-error {{method implementation does not match its declaration}}
+- (Test8*) init24 { return 0; }
+- (Test8*) init34 { return 0; }
+- (Test8*) init44 { return 0; }
+- (Test8*) init54 { return 0; }
+
+- (Test8_complete*) init05 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_complete*) init15 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_complete*) init25 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_complete*) init35 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_complete*) init45 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_complete*) init55 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
+@end
+
+@class Test9_incomplete;
+@interface Test9
+- (Test9_incomplete*) init1; // expected-error {{init methods must return a type related to the receiver type}}
+- (Test9_incomplete*) init2;
+@end
+id test9(Test9 *v) {
+ return [v init1];
+}
+
+// rdar://9491791
+void rdar9491791(int p) {
+ switch (p) {
+ case 3:;
+ NSObject *o = [[NSObject alloc] init]; // expected-note {{jump bypasses initialization of retaining variable}}
+ [o release];
+ break;
+ default: // expected-error {{switch case is in protected scope}}
+ break;
+ }
+}
+
+#define RELEASE_MACRO(x) do { [x release]; } while(1)
+
+// rdar://9504750
+void rdar9504750(id p) {
+ RELEASE_MACRO(p); // expected-error {{ARC forbids explicit message send of 'release'}}
+}
+
+// rdar://8939557
+@interface TestReadonlyProperty : NSObject
+@property(assign,readonly) NSObject *value;
+@end
+
+@implementation TestReadonlyProperty
+@synthesize value;
+- (void)viewDidLoad {
+ value = [NSObject new]; // expected-error {{assigning retained object}}
+}
+@end
+
+// rdar://9601437
+@interface I9601437 {
+ __unsafe_unretained id x;
+}
+-(void)Meth;
+@end
+
+@implementation I9601437
+-(void)Meth {
+ self->x = [NSObject new]; // expected-error {{assigning retained object}}
+}
+@end
diff --git a/test/ARCMT/cxx-checking.mm b/test/ARCMT/cxx-checking.mm
new file mode 100644
index 000000000000..27e0ea3869b8
--- /dev/null
+++ b/test/ARCMT/cxx-checking.mm
@@ -0,0 +1,105 @@
+// RUN: %clang_cc1 -arcmt-check -verify -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fblocks -Warc-abi %s
+
+// Classes that have an Objective-C object pointer.
+struct HasObjectMember0 { // expected-warning{{'HasObjectMember0' cannot be shared between ARC and non-ARC code; add a copy constructor, a copy assignment operator, and a destructor to make it ABI-compatible}}
+ id x;
+};
+
+struct HasObjectMember1 { // expected-warning{{'HasObjectMember1' 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}}
+ id x[3];
+};
+
+struct HasObjectMember2 { // expected-warning{{'HasObjectMember2' 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}}
+ id x[3][2];
+};
+
+// Don't complain if the type has non-external linkage
+namespace {
+ struct HasObjectMember3 {
+ id x[3][2];
+ };
+}
+
+// Don't complain if the Objective-C pointer type was explicitly given
+// no lifetime.
+struct HasObjectMember3 {
+ __unsafe_unretained id x[3][2];
+};
+
+struct HasBlockPointerMember0 { // expected-warning{{'HasBlockPointerMember0' 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}}
+ int (^bp)(int);
+};
+
+struct HasBlockPointerMember1 { // expected-warning{{'HasBlockPointerMember1' 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}}
+ int (^bp[2][3])(int);
+};
+
+struct NonPOD {
+ NonPOD(const NonPOD&);
+};
+
+struct HasObjectMemberAndNonPOD0 { // expected-warning{{'HasObjectMemberAndNonPOD0' cannot be shared between ARC and non-ARC code; add a non-trivial copy assignment operator to make it ABI-compatible}} \
+ // expected-warning{{'HasObjectMemberAndNonPOD0' cannot be shared between ARC and non-ARC code; add a non-trivial destructor to make it ABI-compatible}}
+ id x;
+ NonPOD np;
+};
+
+struct HasObjectMemberAndNonPOD1 { // expected-warning{{'HasObjectMemberAndNonPOD1' cannot be shared between ARC and non-ARC code; add a non-trivial copy assignment operator to make it ABI-compatible}} \
+ // expected-warning{{'HasObjectMemberAndNonPOD1' cannot be shared between ARC and non-ARC code; add a non-trivial destructor to make it ABI-compatible}}
+ NonPOD np;
+ id x[3];
+};
+
+struct HasObjectMemberAndNonPOD2 { // expected-warning{{'HasObjectMemberAndNonPOD2' cannot be shared between ARC and non-ARC code; add a non-trivial copy assignment operator to make it ABI-compatible}} \
+ // expected-warning{{'HasObjectMemberAndNonPOD2' cannot be shared between ARC and non-ARC code; add a non-trivial destructor to make it ABI-compatible}}
+ NonPOD np;
+ id x[3][2];
+};
+
+struct HasObjectMemberAndNonPOD3 {
+ HasObjectMemberAndNonPOD3 &operator=(const HasObjectMemberAndNonPOD3&);
+ ~HasObjectMemberAndNonPOD3();
+ NonPOD np;
+ id x[3][2];
+};
+
+struct HasBlockPointerMemberAndNonPOD0 { // expected-warning{{'HasBlockPointerMemberAndNonPOD0' cannot be shared between ARC and non-ARC code; add a non-trivial copy assignment operator to make it ABI-compatible}} \
+// expected-warning{{'HasBlockPointerMemberAndNonPOD0' cannot be shared between ARC and non-ARC code; add a non-trivial destructor to make it ABI-compatible}}
+ NonPOD np;
+ int (^bp)(int);
+};
+
+struct HasBlockPointerMemberAndNonPOD1 { // expected-warning{{'HasBlockPointerMemberAndNonPOD1' cannot be shared between ARC and non-ARC code; add a non-trivial copy assignment operator to make it ABI-compatible}} \
+// expected-warning{{'HasBlockPointerMemberAndNonPOD1' cannot be shared between ARC and non-ARC code; add a non-trivial destructor to make it ABI-compatible}}
+ NonPOD np;
+ int (^bp[2][3])(int);
+};
+
+int check_non_pod_objc_pointer0[__is_pod(id)? 1 : -1];
+int check_non_pod_objc_pointer1[__is_pod(__strong id)? -1 : 1];
+int check_non_pod_objc_pointer2[__is_pod(__unsafe_unretained id)? 1 : -1];
+int check_non_pod_objc_pointer3[__is_pod(id[2][3])? 1 : -1];
+int check_non_pod_objc_pointer4[__is_pod(__unsafe_unretained id[2][3])? 1 : -1];
+int check_non_pod_block0[__is_pod(int (^)(int))? 1 : -1];
+int check_non_pod_block1[__is_pod(int (^ __unsafe_unretained)(int))? 1 : -1];
+
+struct FlexibleArrayMember0 {
+ int length;
+ id array[]; // expected-error{{flexible array member 'array' of non-POD element type 'id __strong[]'}}
+};
+
+struct FlexibleArrayMember1 {
+ int length;
+ __unsafe_unretained id array[];
+};
+
+// It's okay to pass a retainable type through an ellipsis.
+void variadic(...);
+void test_variadic() {
+ variadic(1, 17, @"Foo");
+}
+
+// It's okay to create a VLA of retainable types.
+void vla(int n) {
+ id vla[n];
+}
diff --git a/test/ARCMT/cxx-rewrite.mm b/test/ARCMT/cxx-rewrite.mm
new file mode 100644
index 000000000000..aba3f7568b03
--- /dev/null
+++ b/test/ARCMT/cxx-rewrite.mm
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c++ %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c++ %s > %t
+// RUN: diff %t %s.result
+
+#include "Common.h"
+
+@interface NSString : NSObject
++(id)string;
+@end
+
+struct foo {
+ NSString *s;
+ foo(NSString *s): s([s retain]){
+ NSAutoreleasePool *pool = [NSAutoreleasePool new];
+ [[[NSString string] retain] release];
+ [pool drain];
+ }
+ ~foo(){ [s release]; }
+private:
+ foo(foo const &);
+ foo &operator=(foo const &);
+};
+
+int main(){
+ NSAutoreleasePool *pool = [NSAutoreleasePool new];
+
+ foo f([[NSString string] autorelease]);
+
+ [pool drain];
+ return 0;
+}
diff --git a/test/ARCMT/cxx-rewrite.mm.result b/test/ARCMT/cxx-rewrite.mm.result
new file mode 100644
index 000000000000..145ccd39e884
--- /dev/null
+++ b/test/ARCMT/cxx-rewrite.mm.result
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c++ %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c++ %s > %t
+// RUN: diff %t %s.result
+
+#include "Common.h"
+
+@interface NSString : NSObject
++(id)string;
+@end
+
+struct foo {
+ NSString *s;
+ foo(NSString *s): s(s){
+ @autoreleasepool {
+ [NSString string];
+ }
+ }
+ ~foo(){ s; }
+private:
+ foo(foo const &);
+ foo &operator=(foo const &);
+};
+
+int main(){
+ @autoreleasepool {
+
+ foo f([NSString string]);
+
+ }
+ return 0;
+}
diff --git a/test/ARCMT/dealloc.m b/test/ARCMT/dealloc.m
new file mode 100644
index 000000000000..dac964403f27
--- /dev/null
+++ b/test/ARCMT/dealloc.m
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// RUN: diff %t %s.result
+
+@interface A
+- (id)retain;
+- (id)autorelease;
+- (oneway void)release;
+- (void)dealloc;
+@end
+
+void test1(A *a) {
+ [a dealloc];
+}
+
+@interface Test2 : A
+- (void) dealloc;
+@end
+
+@implementation Test2
+- (void) dealloc {
+ [super dealloc];
+}
+@end
diff --git a/test/ARCMT/dealloc.m.result b/test/ARCMT/dealloc.m.result
new file mode 100644
index 000000000000..24756d25484b
--- /dev/null
+++ b/test/ARCMT/dealloc.m.result
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// RUN: diff %t %s.result
+
+@interface A
+- (id)retain;
+- (id)autorelease;
+- (oneway void)release;
+- (void)dealloc;
+@end
+
+void test1(A *a) {
+}
+
+@interface Test2 : A
+- (void) dealloc;
+@end
+
+@implementation Test2
+@end
diff --git a/test/ARCMT/driver-migrate.m b/test/ARCMT/driver-migrate.m
new file mode 100644
index 000000000000..e283857cb574
--- /dev/null
+++ b/test/ARCMT/driver-migrate.m
@@ -0,0 +1,3 @@
+// RUN: %clang -### -ccc-arcmt-migrate /foo/bar -fsyntax-only %s 2>&1 | FileCheck %s
+
+// CHECK: "-arcmt-migrate" "-arcmt-migrate-directory" "{{[^"]*}}/foo/bar"
diff --git a/test/ARCMT/init.m b/test/ARCMT/init.m
new file mode 100644
index 000000000000..f0d24f60e1e3
--- /dev/null
+++ b/test/ARCMT/init.m
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// RUN: diff %t %s.result
+
+@interface NSObject
+-init;
+@end
+
+@interface A : NSObject
+-init;
+-init2;
+-foo;
++alloc;
+@end
+
+@implementation A
+-(id) init {
+ [self init];
+ id a;
+ [a init];
+ a = [[A alloc] init];
+
+ return self;
+}
+
+-(id) init2 {
+ [super init];
+ return self;
+}
+
+-(id) foo {
+ [self init];
+ [super init];
+
+ return self;
+}
+@end
diff --git a/test/ARCMT/init.m.result b/test/ARCMT/init.m.result
new file mode 100644
index 000000000000..4f3b4e724e2e
--- /dev/null
+++ b/test/ARCMT/init.m.result
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// RUN: diff %t %s.result
+
+@interface NSObject
+-init;
+@end
+
+@interface A : NSObject
+-init;
+-init2;
+-foo;
++alloc;
+@end
+
+@implementation A
+-(id) init {
+ self = [self init];
+ id a;
+ [a init];
+ a = [[A alloc] init];
+
+ return self;
+}
+
+-(id) init2 {
+ self = [super init];
+ return self;
+}
+
+-(id) foo {
+ [self init];
+ [super init];
+
+ return self;
+}
+@end
diff --git a/test/ARCMT/migrate.m b/test/ARCMT/migrate.m
new file mode 100644
index 000000000000..51029c5204f7
--- /dev/null
+++ b/test/ARCMT/migrate.m
@@ -0,0 +1,4 @@
+// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t %S/Inputs/test1.m.in -x objective-c -fobjc-nonfragile-abi
+// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t %S/Inputs/test2.m.in -x objective-c -fobjc-nonfragile-abi
+// RUN: c-arcmt-test -arcmt-migrate-directory %t | arcmt-test -verify-transformed-files %S/Inputs/test1.m.in.result %S/Inputs/test2.m.in.result %S/Inputs/test.h.result
+// RUN: rm -rf %t
diff --git a/test/ARCMT/nonobjc-to-objc-cast-2.m b/test/ARCMT/nonobjc-to-objc-cast-2.m
new file mode 100644
index 000000000000..46ef02400e8c
--- /dev/null
+++ b/test/ARCMT/nonobjc-to-objc-cast-2.m
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -arcmt-check -verify -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi %s
+
+typedef int BOOL;
+typedef const struct __CFString * CFStringRef;
+
+@class NSString;
+
+void f(BOOL b) {
+ CFStringRef cfstr;
+ NSString *str = (NSString *)cfstr; // expected-error {{cast of C pointer type 'CFStringRef' (aka 'const struct __CFString *') to Objective-C pointer type 'NSString *' requires a bridged cast}} \
+ // expected-note{{use __bridge to convert directly (no change in ownership)}} \
+ // expected-note{{use __bridge_transfer to transfer ownership of a +1 'CFStringRef' (aka 'const struct __CFString *') into ARC}}
+ void *vp = str; // expected-error {{disallowed}}
+}
diff --git a/test/ARCMT/nonobjc-to-objc-cast.m b/test/ARCMT/nonobjc-to-objc-cast.m
new file mode 100644
index 000000000000..4e1e293efbac
--- /dev/null
+++ b/test/ARCMT/nonobjc-to-objc-cast.m
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// RUN: diff %t %s.result
+
+#include "Common.h"
+
+@interface NSString : NSObject
+@end
+
+typedef const struct __CFString * CFStringRef;
+extern const CFStringRef kUTTypePlainText;
+extern const CFStringRef kUTTypeRTF;
+
+typedef const struct __CFAllocator * CFAllocatorRef;
+typedef const struct __CFUUID * CFUUIDRef;
+
+extern const CFAllocatorRef kCFAllocatorDefault;
+
+extern CFStringRef CFUUIDCreateString(CFAllocatorRef alloc, CFUUIDRef uuid);
+
+void f(BOOL b, id p) {
+ NSString *str = (NSString *)kUTTypePlainText;
+ str = b ? kUTTypeRTF : kUTTypePlainText;
+ str = (NSString *)(b ? kUTTypeRTF : kUTTypePlainText);
+ str = (NSString *)p; // no change.
+
+ CFUUIDRef _uuid;
+ NSString *_uuidString = (NSString *)CFUUIDCreateString(kCFAllocatorDefault, _uuid);
+ _uuidString = [(NSString *)CFUUIDCreateString(kCFAllocatorDefault, _uuid) autorelease];
+}
+
+@implementation NSString (StrExt)
+- (NSString *)stringEscapedAsURI {
+ CFStringRef str = (CFStringRef)self;
+ CFStringRef str2 = self;
+ return self;
+}
+@end
diff --git a/test/ARCMT/nonobjc-to-objc-cast.m.result b/test/ARCMT/nonobjc-to-objc-cast.m.result
new file mode 100644
index 000000000000..53dde7553d6d
--- /dev/null
+++ b/test/ARCMT/nonobjc-to-objc-cast.m.result
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// RUN: diff %t %s.result
+
+#include "Common.h"
+
+@interface NSString : NSObject
+@end
+
+typedef const struct __CFString * CFStringRef;
+extern const CFStringRef kUTTypePlainText;
+extern const CFStringRef kUTTypeRTF;
+
+typedef const struct __CFAllocator * CFAllocatorRef;
+typedef const struct __CFUUID * CFUUIDRef;
+
+extern const CFAllocatorRef kCFAllocatorDefault;
+
+extern CFStringRef CFUUIDCreateString(CFAllocatorRef alloc, CFUUIDRef uuid);
+
+void f(BOOL b, id p) {
+ NSString *str = (__bridge NSString *)kUTTypePlainText;
+ str = (__bridge NSString *)(b ? kUTTypeRTF : kUTTypePlainText);
+ str = (__bridge NSString *)(b ? kUTTypeRTF : kUTTypePlainText);
+ str = (NSString *)p; // no change.
+
+ CFUUIDRef _uuid;
+ NSString *_uuidString = (__bridge_transfer NSString *)CFUUIDCreateString(kCFAllocatorDefault, _uuid);
+ _uuidString = (__bridge_transfer NSString *)CFUUIDCreateString(kCFAllocatorDefault, _uuid);
+}
+
+@implementation NSString (StrExt)
+- (NSString *)stringEscapedAsURI {
+ CFStringRef str = (__bridge CFStringRef)self;
+ CFStringRef str2 = (__bridge CFStringRef)(self);
+ return self;
+}
+@end
diff --git a/test/ARCMT/releases-driver.m b/test/ARCMT/releases-driver.m
new file mode 100644
index 000000000000..a016b26f4482
--- /dev/null
+++ b/test/ARCMT/releases-driver.m
@@ -0,0 +1,68 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fblocks -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: cp %s %t
+// RUN: %clang_cc1 -arcmt-modify -triple x86_64-apple-macosx10.6 -fobjc-nonfragile-abi -x objective-c %t
+// RUN: diff %t %s.result
+// RUN: rm %t
+
+typedef int BOOL;
+
+id IhaveSideEffect();
+
+@protocol NSObject
+- (BOOL)isEqual:(id)object;
+- (id)retain;
+- (oneway void)release;
+@end
+
+@interface NSObject <NSObject> {}
+@end
+
+@interface Foo : NSObject {
+ id bar;
+}
+@property (retain) id bar;
+-(void)test:(id)obj;
+@end
+
+@implementation Foo
+
+@synthesize bar;
+
+-(void)test:(id)obj {
+ id x = self.bar;
+ [x retain];
+ self.bar = obj;
+ // do stuff with x;
+ [x release];
+
+ [IhaveSideEffect() release];
+
+ [x release], x = 0;
+}
+
+@end
+
+void func(Foo *p) {
+ [p release];
+ (([p release]));
+}
+
+@interface Baz {
+ id <NSObject> _foo;
+}
+@end
+
+@implementation Baz
+- dealloc {
+ [_foo release];
+ return 0;
+}
+@end
+
+#define RELEASE_MACRO(x) [x release]
+#define RELEASE_MACRO2(x) RELEASE_MACRO(x)
+
+void test2(id p) {
+ RELEASE_MACRO(p);
+ RELEASE_MACRO2(p);
+}
diff --git a/test/ARCMT/releases-driver.m.result b/test/ARCMT/releases-driver.m.result
new file mode 100644
index 000000000000..c5f527fec1c1
--- /dev/null
+++ b/test/ARCMT/releases-driver.m.result
@@ -0,0 +1,61 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fblocks -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: cp %s %t
+// RUN: %clang_cc1 -arcmt-modify -triple x86_64-apple-macosx10.6 -fobjc-nonfragile-abi -x objective-c %t
+// RUN: diff %t %s.result
+// RUN: rm %t
+
+typedef int BOOL;
+
+id IhaveSideEffect();
+
+@protocol NSObject
+- (BOOL)isEqual:(id)object;
+- (id)retain;
+- (oneway void)release;
+@end
+
+@interface NSObject <NSObject> {}
+@end
+
+@interface Foo : NSObject {
+ id bar;
+}
+@property (strong) id bar;
+-(void)test:(id)obj;
+@end
+
+@implementation Foo
+
+@synthesize bar;
+
+-(void)test:(id)obj {
+ id x = self.bar;
+ self.bar = obj;
+ // do stuff with x;
+
+ IhaveSideEffect();
+
+ x = 0;
+}
+
+@end
+
+void func(Foo *p) {
+}
+
+@interface Baz {
+ id <NSObject> _foo;
+}
+@end
+
+@implementation Baz
+- dealloc {
+ return 0;
+}
+@end
+
+#define RELEASE_MACRO(x) [x release]
+#define RELEASE_MACRO2(x) RELEASE_MACRO(x)
+
+void test2(id p) {
+}
diff --git a/test/ARCMT/releases.m b/test/ARCMT/releases.m
new file mode 100644
index 000000000000..d5f21dc4c2a7
--- /dev/null
+++ b/test/ARCMT/releases.m
@@ -0,0 +1,87 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fobjc-exceptions -fblocks -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-exceptions -fblocks -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// RUN: diff %t %s.result
+
+#define nil 0
+
+typedef int BOOL;
+
+id IhaveSideEffect();
+
+@protocol NSObject
+- (BOOL)isEqual:(id)object;
+- (id)retain;
+- (oneway void)release;
+@end
+
+@interface NSObject <NSObject> {}
+@end
+
+@interface Foo : NSObject {
+ id bar;
+}
+@property (retain) id bar;
+-(void)test:(id)obj;
+@end
+
+@implementation Foo
+
+@synthesize bar;
+
+-(void)test:(id)obj {
+ id x = self.bar;
+ [x retain];
+ self.bar = obj;
+ // do stuff with x;
+ [x release];
+
+ [IhaveSideEffect() release];
+
+ [x release], x = 0;
+
+ @try {
+ } @finally {
+ [x release];
+ }
+}
+
+@end
+
+void func(Foo *p) {
+ [p release];
+ (([p release]));
+}
+
+@interface Baz {
+ id <NSObject> _foo;
+}
+@end
+
+@implementation Baz
+- dealloc {
+ [_foo release];
+ return 0;
+}
+@end
+
+void block_test(Foo *p) {
+ id (^B)() = ^() {
+ if (p) {
+ id (^IB)() = ^() {
+ id bar = [p retain];
+ [p release];
+ return bar;
+ };
+ IB();
+ }
+ return [p retain];
+ };
+}
+
+#define RELEASE_MACRO(x) [x release]
+#define RELEASE_MACRO2(x) RELEASE_MACRO(x)
+
+void test2(id p) {
+ RELEASE_MACRO(p);
+ RELEASE_MACRO2(p);
+}
diff --git a/test/ARCMT/releases.m.result b/test/ARCMT/releases.m.result
new file mode 100644
index 000000000000..1d36f3e6b7de
--- /dev/null
+++ b/test/ARCMT/releases.m.result
@@ -0,0 +1,79 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fobjc-exceptions -fblocks -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-exceptions -fblocks -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// RUN: diff %t %s.result
+
+#define nil 0
+
+typedef int BOOL;
+
+id IhaveSideEffect();
+
+@protocol NSObject
+- (BOOL)isEqual:(id)object;
+- (id)retain;
+- (oneway void)release;
+@end
+
+@interface NSObject <NSObject> {}
+@end
+
+@interface Foo : NSObject {
+ id bar;
+}
+@property (strong) id bar;
+-(void)test:(id)obj;
+@end
+
+@implementation Foo
+
+@synthesize bar;
+
+-(void)test:(id)obj {
+ id x = self.bar;
+ self.bar = obj;
+ // do stuff with x;
+
+ IhaveSideEffect();
+
+ x = 0;
+
+ @try {
+ } @finally {
+ x = nil;
+ }
+}
+
+@end
+
+void func(Foo *p) {
+}
+
+@interface Baz {
+ id <NSObject> _foo;
+}
+@end
+
+@implementation Baz
+- dealloc {
+ return 0;
+}
+@end
+
+void block_test(Foo *p) {
+ id (^B)() = ^() {
+ if (p) {
+ id (^IB)() = ^() {
+ id bar = p;
+ return bar;
+ };
+ IB();
+ }
+ return p;
+ };
+}
+
+#define RELEASE_MACRO(x) [x release]
+#define RELEASE_MACRO2(x) RELEASE_MACRO(x)
+
+void test2(id p) {
+}
diff --git a/test/ARCMT/remove-dealloc-method.m b/test/ARCMT/remove-dealloc-method.m
new file mode 100644
index 000000000000..5c2d785ba716
--- /dev/null
+++ b/test/ARCMT/remove-dealloc-method.m
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// RUN: diff %t %s.result
+
+#define nil ((void*) 0)
+
+@interface Foo
+@property (retain) id x;
+@property (retain) id y;
+@property (retain) id w;
+@property (retain) id z;
+@end
+
+@implementation Foo
+@synthesize x;
+@synthesize y;
+@synthesize w;
+@synthesize z;
+
+- (void) dealloc {
+ self.x = 0;
+ [self setY:nil];
+ w = nil;
+ self.z = nil;
+}
+@end
diff --git a/test/ARCMT/remove-dealloc-method.m.result b/test/ARCMT/remove-dealloc-method.m.result
new file mode 100644
index 000000000000..ecb752cf2f88
--- /dev/null
+++ b/test/ARCMT/remove-dealloc-method.m.result
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// RUN: diff %t %s.result
+
+#define nil ((void*) 0)
+
+@interface Foo
+@property (strong) id x;
+@property (strong) id y;
+@property (strong) id w;
+@property (strong) id z;
+@end
+
+@implementation Foo
+@synthesize x;
+@synthesize y;
+@synthesize w;
+@synthesize z;
+
+@end
diff --git a/test/ARCMT/remove-dealloc-zerouts.m b/test/ARCMT/remove-dealloc-zerouts.m
new file mode 100644
index 000000000000..3ba85f1edcab
--- /dev/null
+++ b/test/ARCMT/remove-dealloc-zerouts.m
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// RUN: diff %t %s.result
+
+@interface Foo
+@property (retain) id x;
+@property (retain) id y;
+@property (retain) id w;
+@property (retain) id z;
+@property (strong) id q;
+@end
+
+@implementation Foo
+@synthesize x;
+@synthesize y;
+@synthesize w;
+@synthesize q;
+@dynamic z;
+
+- (void) dealloc {
+ self.x = self.y = self.w = 0;
+ self.x = 0, w = 0, y = 0;
+ [self setY:0];
+ w = 0;
+ q = 0;
+ self.z = 0;
+}
+@end
+
+@interface Bar
+@property (retain) Foo *a;
+- (void) setA:(Foo*) val;
+- (id) a;
+@end
+
+@implementation Bar
+- (void) dealloc {
+ [self setA:0]; // This is user-defined setter overriding synthesize, don't touch it.
+ self.a.x = 0; // every dealloc must zero out its own ivar. This patter is not recognized.
+}
+@synthesize a;
+- (void) setA:(Foo*) val { }
+- (id) a {return 0;}
+@end
diff --git a/test/ARCMT/remove-dealloc-zerouts.m.result b/test/ARCMT/remove-dealloc-zerouts.m.result
new file mode 100644
index 000000000000..dc6ffd311490
--- /dev/null
+++ b/test/ARCMT/remove-dealloc-zerouts.m.result
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// RUN: diff %t %s.result
+
+@interface Foo
+@property (strong) id x;
+@property (strong) id y;
+@property (strong) id w;
+@property (strong) id z;
+@property (strong) id q;
+@end
+
+@implementation Foo
+@synthesize x;
+@synthesize y;
+@synthesize w;
+@synthesize q;
+@dynamic z;
+
+- (void) dealloc {
+ self.z = 0;
+}
+@end
+
+@interface Bar
+@property (strong) Foo *a;
+- (void) setA:(Foo*) val;
+- (id) a;
+@end
+
+@implementation Bar
+- (void) dealloc {
+ [self setA:0]; // This is user-defined setter overriding synthesize, don't touch it.
+ self.a.x = 0; // every dealloc must zero out its own ivar. This patter is not recognized.
+}
+@synthesize a;
+- (void) setA:(Foo*) val { }
+- (id) a {return 0;}
+@end
diff --git a/test/ARCMT/remove-statements.m b/test/ARCMT/remove-statements.m
new file mode 100644
index 000000000000..7e102961263a
--- /dev/null
+++ b/test/ARCMT/remove-statements.m
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// RUN: diff %t %s.result
+
+#include "Common.h"
+
+@interface myController : NSObject
+-(id)test:(id)x;
+@end
+
+#define MY_MACRO1(x)
+#define MY_MACRO2(x) (void)x
+
+@implementation myController
+-(id) test:(id) x {
+ [[x retain] release];
+ return [[x retain] autorelease];
+}
+
+-(void)dealloc
+{
+ id array, array_already_empty;
+ for (id element in array_already_empty) {
+ }
+
+ [array release];
+ ;
+
+ int b, b_array_already_empty;
+ if (b)
+ [array release];
+ if (b_array_already_empty) ;
+
+ if (b) {
+ [array release];
+ }
+ if (b_array_already_empty) {
+ }
+
+ if (b)
+ MY_MACRO1(array);
+ if (b)
+ MY_MACRO2(array);
+}
+@end
diff --git a/test/ARCMT/remove-statements.m.result b/test/ARCMT/remove-statements.m.result
new file mode 100644
index 000000000000..9a1153e287c2
--- /dev/null
+++ b/test/ARCMT/remove-statements.m.result
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// RUN: diff %t %s.result
+
+#include "Common.h"
+
+@interface myController : NSObject
+-(id)test:(id)x;
+@end
+
+#define MY_MACRO1(x)
+#define MY_MACRO2(x) (void)x
+
+@implementation myController
+-(id) test:(id) x {
+ return x;
+}
+
+-(void)dealloc
+{
+ id array, array_already_empty;
+ for (id element in array_already_empty) {
+ }
+
+ ;
+
+ int b, b_array_already_empty;
+ if (b_array_already_empty) ;
+
+ if (b_array_already_empty) {
+ }
+
+ if (b)
+ MY_MACRO1(array);
+ if (b)
+ MY_MACRO2(array);
+}
+@end
diff --git a/test/ARCMT/retains.m b/test/ARCMT/retains.m
new file mode 100644
index 000000000000..fa90f218dd5d
--- /dev/null
+++ b/test/ARCMT/retains.m
@@ -0,0 +1,71 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fblocks -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fblocks -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// RUN: diff %t %s.result
+
+#include "Common.h"
+
+id IhaveSideEffect();
+
+@interface Foo : NSObject {
+ id bar;
+}
+@property (retain) id bar;
+-(id)test:(id)obj;
+-(id)something;
+@end
+
+#define Something_Macro(key, comment) \
+ [[Foo new] something]
+
+@implementation Foo
+
+@synthesize bar;
+
+-(id)something {}
+
+-(id)test:(id)obj {
+ id x = self.bar;
+ [x retain];
+ self.bar = obj;
+ if (obj)
+ [obj retain];
+
+ [Something_Macro(@"foo", "@bar") retain];
+
+ [IhaveSideEffect() retain];
+
+ [[self something] retain];
+
+ [[self retain] something];
+
+ [[IhaveSideEffect() retain] release];
+ [[x retain] release];
+ // do stuff with x;
+ [x release];
+ return [self retain];
+}
+
+- (id)test1 {
+ id x=0;
+ ([x retain]);
+ return ((([x retain])));
+}
+@end
+
+id foo (Foo *p) {
+ p = [p retain];
+ return ([p retain]);
+}
+
+void block_tests(Foo *p) {
+ id (^B)() = ^() {
+ if (p) {
+ id (^IB)() = ^() {
+ id bar = [p retain];
+ return bar;
+ };
+ IB();
+ }
+ return [p retain];
+ };
+}
diff --git a/test/ARCMT/retains.m.result b/test/ARCMT/retains.m.result
new file mode 100644
index 000000000000..54df864e58cb
--- /dev/null
+++ b/test/ARCMT/retains.m.result
@@ -0,0 +1,65 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fblocks -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fblocks -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// RUN: diff %t %s.result
+
+#include "Common.h"
+
+id IhaveSideEffect();
+
+@interface Foo : NSObject {
+ id bar;
+}
+@property (strong) id bar;
+-(id)test:(id)obj;
+-(id)something;
+@end
+
+#define Something_Macro(key, comment) \
+ [[Foo new] something]
+
+@implementation Foo
+
+@synthesize bar;
+
+-(id)something {}
+
+-(id)test:(id)obj {
+ id x = self.bar;
+ self.bar = obj;
+
+ Something_Macro(@"foo", "@bar");
+
+ IhaveSideEffect();
+
+ [self something];
+
+ [self something];
+
+ IhaveSideEffect();
+ // do stuff with x;
+ return self;
+}
+
+- (id)test1 {
+ id x=0;
+ return (((x)));
+}
+@end
+
+id foo (Foo *p) {
+ p = p;
+ return (p);
+}
+
+void block_tests(Foo *p) {
+ id (^B)() = ^() {
+ if (p) {
+ id (^IB)() = ^() {
+ id bar = p;
+ return bar;
+ };
+ IB();
+ }
+ return p;
+ };
+}
diff --git a/test/ARCMT/rewrite-block-var.m b/test/ARCMT/rewrite-block-var.m
new file mode 100644
index 000000000000..81407f92e9bb
--- /dev/null
+++ b/test/ARCMT/rewrite-block-var.m
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fblocks -fsyntax-only -fobjc-arc -x objective-c -fobjc-runtime-has-weak %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-macosx10.7 -fobjc-nonfragile-abi -fblocks -fsyntax-only %s > %t
+// RUN: diff %t %s.result
+
+#include "Common.h"
+
+@interface Foo : NSObject
+-(Foo *)something;
+@end
+
+void bar(void (^block)());
+
+void test1(Foo *p) {
+ __block Foo *x = p; // __block used just to break cycle.
+ bar(^{
+ [x something];
+ });
+}
+
+void test2(Foo *p) {
+ __block Foo *x; // __block used as output variable.
+ bar(^{
+ x = [p something];
+ });
+}
diff --git a/test/ARCMT/rewrite-block-var.m.result b/test/ARCMT/rewrite-block-var.m.result
new file mode 100644
index 000000000000..85093ac52d27
--- /dev/null
+++ b/test/ARCMT/rewrite-block-var.m.result
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fblocks -fsyntax-only -fobjc-arc -x objective-c -fobjc-runtime-has-weak %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-macosx10.7 -fobjc-nonfragile-abi -fblocks -fsyntax-only %s > %t
+// RUN: diff %t %s.result
+
+#include "Common.h"
+
+@interface Foo : NSObject
+-(Foo *)something;
+@end
+
+void bar(void (^block)());
+
+void test1(Foo *p) {
+ __weak Foo *x = p; // __block used just to break cycle.
+ bar(^{
+ [x something];
+ });
+}
+
+void test2(Foo *p) {
+ __block Foo *x; // __block used as output variable.
+ bar(^{
+ x = [p something];
+ });
+}
diff --git a/test/ARCMT/safe-arc-assign.m b/test/ARCMT/safe-arc-assign.m
new file mode 100644
index 000000000000..368c2b6639da
--- /dev/null
+++ b/test/ARCMT/safe-arc-assign.m
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// RUN: diff %t %s.result
+
+void test12(id collection) {
+ for (id x in collection) {
+ x = 0;
+ x = 0;
+ }
+
+ for (__strong id x in collection) {
+ x = 0;
+ }
+}
diff --git a/test/ARCMT/safe-arc-assign.m.result b/test/ARCMT/safe-arc-assign.m.result
new file mode 100644
index 000000000000..cacd1093c524
--- /dev/null
+++ b/test/ARCMT/safe-arc-assign.m.result
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// RUN: diff %t %s.result
+
+void test12(id collection) {
+ for (__strong id x in collection) {
+ x = 0;
+ x = 0;
+ }
+
+ for (__strong id x in collection) {
+ x = 0;
+ }
+}
diff --git a/test/ARCMT/with-arc-mode-check.m b/test/ARCMT/with-arc-mode-check.m
new file mode 100644
index 000000000000..c3146ef3b614
--- /dev/null
+++ b/test/ARCMT/with-arc-mode-check.m
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -arcmt-check -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s
+
+@protocol NSObject
+- (oneway void)release;
+@end
+
+void test1(id p) {
+ [p release];
+}
diff --git a/test/ARCMT/with-arc-mode-migrate.m b/test/ARCMT/with-arc-mode-migrate.m
new file mode 100644
index 000000000000..3851bc77312e
--- /dev/null
+++ b/test/ARCMT/with-arc-mode-migrate.m
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc %s
+// RUN: c-arcmt-test -arcmt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+// RUN: rm -rf %t
+
+@protocol NSObject
+- (oneway void)release;
+@end
+
+void test1(id p) {
+ [p release];
+}
diff --git a/test/ARCMT/with-arc-mode-migrate.m.result b/test/ARCMT/with-arc-mode-migrate.m.result
new file mode 100644
index 000000000000..c2222ae7b659
--- /dev/null
+++ b/test/ARCMT/with-arc-mode-migrate.m.result
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc %s
+// RUN: c-arcmt-test -arcmt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+// RUN: rm -rf %t
+
+@protocol NSObject
+- (oneway void)release;
+@end
+
+void test1(id p) {
+}
diff --git a/test/ARCMT/with-arc-mode-modify.m b/test/ARCMT/with-arc-mode-modify.m
new file mode 100644
index 000000000000..17a398072e1f
--- /dev/null
+++ b/test/ARCMT/with-arc-mode-modify.m
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: cp %s %t
+// RUN: %clang_cc1 -arcmt-modify -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %t
+// RUN: diff %t %s.result
+// RUN: rm %t
+
+@protocol NSObject
+- (oneway void)release;
+@end
+
+void test1(id p) {
+ [p release];
+}
diff --git a/test/ARCMT/with-arc-mode-modify.m.result b/test/ARCMT/with-arc-mode-modify.m.result
new file mode 100644
index 000000000000..97c5128cd950
--- /dev/null
+++ b/test/ARCMT/with-arc-mode-modify.m.result
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: cp %s %t
+// RUN: %clang_cc1 -arcmt-modify -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %t
+// RUN: diff %t %s.result
+// RUN: rm %t
+
+@protocol NSObject
+- (oneway void)release;
+@end
+
+void test1(id p) {
+}
diff --git a/test/Analysis/bstring.c b/test/Analysis/bstring.c
index 68bbb1a5b2f5..cd43e36d0351 100644
--- a/test/Analysis/bstring.c
+++ b/test/Analysis/bstring.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.experimental.CString -analyzer-store=region -Wno-null-dereference -verify %s
-// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,cplusplus.experimental.CString -analyzer-store=region -Wno-null-dereference -verify %s
-// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-checker=core,cplusplus.experimental.CString -analyzer-store=region -Wno-null-dereference -verify %s
-// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=core,cplusplus.experimental.CString -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.experimental.CString -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,unix.experimental.CString -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-checker=core,unix.experimental.CString -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=core,unix.experimental.CString -analyzer-store=region -Wno-null-dereference -verify %s
//===----------------------------------------------------------------------===
// Declarations
@@ -64,14 +64,14 @@ void memcpy1 () {
char src[] = {1, 2, 3, 4};
char dst[10];
- memcpy(dst, src, 5); // expected-warning{{Byte string function accesses out-of-bound array element}}
+ memcpy(dst, src, 5); // expected-warning{{Memory copy function accesses out-of-bound array element}}
}
void memcpy2 () {
char src[] = {1, 2, 3, 4};
char dst[1];
- memcpy(dst, src, 4); // expected-warning{{Byte string function overflows destination buffer}}
+ memcpy(dst, src, 4); // expected-warning{{Memory copy function overflows destination buffer}}
}
void memcpy3 () {
@@ -85,14 +85,14 @@ void memcpy4 () {
char src[] = {1, 2, 3, 4};
char dst[10];
- memcpy(dst+2, src+2, 3); // expected-warning{{Byte string function accesses out-of-bound array element}}
+ memcpy(dst+2, src+2, 3); // expected-warning{{Memory copy function accesses out-of-bound array element}}
}
void memcpy5() {
char src[] = {1, 2, 3, 4};
char dst[3];
- memcpy(dst+2, src+2, 2); // expected-warning{{Byte string function overflows destination buffer}}
+ memcpy(dst+2, src+2, 2); // expected-warning{{Memory copy function overflows destination buffer}}
}
void memcpy6() {
@@ -118,12 +118,12 @@ void memcpy9() {
void memcpy10() {
char a[4] = {0};
- memcpy(0, a, 4); // expected-warning{{Null pointer argument in call to byte string function}}
+ memcpy(0, a, 4); // expected-warning{{Null pointer argument in call to memory copy function}}
}
void memcpy11() {
char a[4] = {0};
- memcpy(a, 0, 4); // expected-warning{{Null pointer argument in call to byte string function}}
+ memcpy(a, 0, 4); // expected-warning{{Null pointer argument in call to memory copy function}}
}
void memcpy12() {
@@ -144,7 +144,7 @@ void memcpy_unknown_size (size_t n) {
void memcpy_unknown_size_warn (size_t n) {
char a[4];
- if (memcpy(a, 0, n) != a) // expected-warning{{Null pointer argument in call to byte string function}}
+ if (memcpy(a, 0, n) != a) // expected-warning{{Null pointer argument in call to memory copy function}}
(void)*(char*)0; // no-warning
}
@@ -186,14 +186,14 @@ void mempcpy1 () {
char src[] = {1, 2, 3, 4};
char dst[10];
- mempcpy(dst, src, 5); // expected-warning{{Byte string function accesses out-of-bound array element}}
+ mempcpy(dst, src, 5); // expected-warning{{Memory copy function accesses out-of-bound array element}}
}
void mempcpy2 () {
char src[] = {1, 2, 3, 4};
char dst[1];
- mempcpy(dst, src, 4); // expected-warning{{Byte string function overflows destination buffer}}
+ mempcpy(dst, src, 4); // expected-warning{{Memory copy function overflows destination buffer}}
}
void mempcpy3 () {
@@ -207,14 +207,14 @@ void mempcpy4 () {
char src[] = {1, 2, 3, 4};
char dst[10];
- mempcpy(dst+2, src+2, 3); // expected-warning{{Byte string function accesses out-of-bound array element}}
+ mempcpy(dst+2, src+2, 3); // expected-warning{{Memory copy function accesses out-of-bound array element}}
}
void mempcpy5() {
char src[] = {1, 2, 3, 4};
char dst[3];
- mempcpy(dst+2, src+2, 2); // expected-warning{{Byte string function overflows destination buffer}}
+ mempcpy(dst+2, src+2, 2); // expected-warning{{Memory copy function overflows destination buffer}}
}
void mempcpy6() {
@@ -240,12 +240,12 @@ void mempcpy9() {
void mempcpy10() {
char a[4] = {0};
- mempcpy(0, a, 4); // expected-warning{{Null pointer argument in call to byte string function}}
+ mempcpy(0, a, 4); // expected-warning{{Null pointer argument in call to memory copy function}}
}
void mempcpy11() {
char a[4] = {0};
- mempcpy(a, 0, 4); // expected-warning{{Null pointer argument in call to byte string function}}
+ mempcpy(a, 0, 4); // expected-warning{{Null pointer argument in call to memory copy function}}
}
void mempcpy12() {
@@ -260,7 +260,7 @@ void mempcpy13() {
void mempcpy_unknown_size_warn (size_t n) {
char a[4];
- if (mempcpy(a, 0, n) != a) // expected-warning{{Null pointer argument in call to byte string function}}
+ if (mempcpy(a, 0, n) != a) // expected-warning{{Null pointer argument in call to memory copy function}}
(void)*(char*)0; // no-warning
}
diff --git a/test/Analysis/misc-ps-eager-assume.m b/test/Analysis/misc-ps-eager-assume.m
index 649c4b07f543..4380a187b800 100644
--- a/test/Analysis/misc-ps-eager-assume.m
+++ b/test/Analysis/misc-ps-eager-assume.m
@@ -12,6 +12,7 @@ typedef struct _NSZone NSZone;
@end @protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder;
@end @interface NSObject <NSObject> {}
+ (id)alloc;
+- (id)init;
@end typedef struct {}
NSFastEnumerationState;
@protocol NSFastEnumeration - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len;
diff --git a/test/Analysis/nullptr.cpp b/test/Analysis/nullptr.cpp
index b74a5abcdfa4..6f78baebfe22 100644
--- a/test/Analysis/nullptr.cpp
+++ b/test/Analysis/nullptr.cpp
@@ -39,3 +39,11 @@ void foo4(void) {
*np = 0; // no-warning
}
+
+int pr10372(void *& x) {
+ // GNU null is a pointer-sized integer, not a pointer.
+ x = __null;
+ // This used to crash.
+ return __null;
+}
+
diff --git a/test/Analysis/objc-arc.m b/test/Analysis/objc-arc.m
new file mode 100644
index 000000000000..6b22fd099b06
--- /dev/null
+++ b/test/Analysis/objc-arc.m
@@ -0,0 +1,149 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core -analyzer-checker=deadcode -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks -fobjc-nonfragile-abi -fobjc-arc %s
+
+typedef signed char BOOL;
+typedef struct _NSZone NSZone;
+@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
+
+@protocol NSObject
+- (BOOL)isEqual:(id)object;
+@end
+@protocol NSCopying
+- (id)copyWithZone:(NSZone *)zone;
+@end
+@protocol NSCoding
+- (void)encodeWithCoder:(NSCoder *)aCoder;
+@end
+@interface NSObject <NSObject> {}
++ (id)alloc;
+@end
+typedef const struct __CFAllocator * CFAllocatorRef;
+extern const CFAllocatorRef kCFAllocatorDefault;
+typedef double CFTimeInterval;
+typedef CFTimeInterval CFAbsoluteTime;
+extern CFAbsoluteTime CFAbsoluteTimeGetCurrent(void);
+typedef const struct __CFDate * CFDateRef;
+extern CFDateRef CFDateCreate(CFAllocatorRef allocator, CFAbsoluteTime at);
+
+typedef const void* objc_objectptr_t;
+__attribute__((ns_returns_retained)) id objc_retainedObject(objc_objectptr_t __attribute__((cf_consumed)) pointer);
+__attribute__((ns_returns_not_retained)) id objc_unretainedObject(objc_objectptr_t pointer);
+
+// Test the analyzer is working at all.
+void test_working() {
+ int *p = 0;
+ *p = 0xDEADBEEF; // expected-warning {{null}}
+}
+
+// Test that in ARC mode that blocks are correctly automatically copied
+// and not flagged as warnings by the analyzer.
+typedef void (^Block)(void);
+void testblock_bar(int x);
+
+Block testblock_foo(int x) {
+ Block b = ^{ testblock_bar(x); };
+ return b; // no-warning
+}
+
+Block testblock_baz(int x) {
+ return ^{ testblock_bar(x); }; // no-warning
+}
+
+Block global_block;
+
+void testblock_qux(int x) {
+ global_block = ^{ testblock_bar(x); }; // no-warning
+}
+
+// Test that Objective-C pointers are null initialized.
+void test_nil_initialized() {
+ id x;
+ if (x == 0)
+ return;
+ int *p = 0;
+ *p = 0xDEADBEEF; // no-warning
+}
+
+// Test that we don't flag leaks of Objective-C objects.
+void test_alloc() {
+ [NSObject alloc]; // no-warning
+}
+
+// Test that CF allocations are still caught as leaks.
+void test_cf_leak() {
+ CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
+ CFDateRef date = CFDateCreate(0, t); // expected-warning {{Potential leak}}
+ (void) date;
+}
+
+// Test that 'init' methods do not try to claim ownerhip of an *unowned* allocated object
+// in ARC mode.
+@interface RDar9424890_A : NSObject
+- (id)initWithCleaner:(int)pop mop:(NSString *)mop ;
+- (RDar9424890_A *)rdar9424890:(NSString *)identifier;
+@end
+@interface RDar9424890_B : NSObject
+@end
+@implementation RDar9424890_B
+- (RDar9424890_A *)obj:(RDar9424890_A *)obj {
+ static NSString *WhizFiz = @"WhizFiz";
+ RDar9424890_A *cell = [obj rdar9424890:WhizFiz];
+ if (cell == ((void*)0)) {
+ cell = [[RDar9424890_A alloc] initWithCleaner:0 mop:WhizFiz]; // no-warning
+ }
+ return cell;
+}
+@end
+
+// Test that dead store checking works in the prescence of "cleanups" in the AST.
+void rdar9424882() {
+ id x = [NSObject alloc]; // expected-warning {{Value stored to 'x' during its initialization is never read}}
+}
+
+// Test
+typedef const void *CFTypeRef;
+typedef const struct __CFString *CFStringRef;
+
+@interface NSString
+- (id) self;
+@end
+
+CFTypeRef CFCreateSomething();
+CFStringRef CFCreateString();
+CFTypeRef CFGetSomething();
+CFStringRef CFGetString();
+
+id CreateSomething();
+NSString *CreateNSString();
+
+void from_cf() {
+ id obj1 = (__bridge_transfer id)CFCreateSomething(); // expected-warning{{never read}}
+ id obj2 = (__bridge_transfer NSString*)CFCreateString();
+ [obj2 self]; // Add a use, to show we can use the object after it has been transfered.
+ id obj3 = (__bridge id)CFGetSomething();
+ [obj3 self]; // Add a use, to show we can use the object after it has been bridged.
+ id obj4 = (__bridge NSString*)CFGetString(); // expected-warning{{never read}}
+ id obj5 = (__bridge id)CFCreateSomething(); // expected-warning{{never read}} expected-warning{{leak}}
+ id obj6 = (__bridge NSString*)CFCreateString(); // expected-warning{{never read}} expected-warning{{leak}}
+}
+
+void to_cf(id obj) {
+ CFTypeRef cf1 = (__bridge_retained CFTypeRef)CreateSomething(); // expected-warning{{never read}}
+ CFStringRef cf2 = (__bridge_retained CFStringRef)CreateNSString(); // expected-warning{{never read}}
+ CFTypeRef cf3 = (__bridge CFTypeRef)CreateSomething(); // expected-warning{{never read}}
+ CFStringRef cf4 = (__bridge CFStringRef)CreateNSString(); // expected-warning{{never read}}
+}
+
+void test_objc_retainedObject() {
+ CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
+ CFDateRef date = CFDateCreate(0, t);
+ id x = objc_retainedObject(date);
+ (void) x;
+}
+
+void test_objc_unretainedObject() {
+ CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
+ CFDateRef date = CFDateCreate(0, t); // expected-warning {{Potential leak}}
+ id x = objc_unretainedObject(date);
+ (void) x;
+}
+
diff --git a/test/Analysis/pr4209.m b/test/Analysis/pr4209.m
index 1e0fd32fcd03..e3bc5cc14333 100644
--- a/test/Analysis/pr4209.m
+++ b/test/Analysis/pr4209.m
@@ -49,17 +49,17 @@ CMProfileLocation;
GSEbayCategory *rootCategory;
}
- (NSMutableDictionary*)categoryDictionaryForCategoryID:(int)inID inRootTreeCategories:(NSMutableArray*)inRootTreeCategories; // expected-note {{method definition for 'categoryDictionaryForCategoryID:inRootTreeCategories:' not found}}
--(NSString*) categoryID; // expected-note {{method definition for 'categoryID' not found}}
+-(NSString*) categoryID; // expected-note {{method definition for 'categoryID' not found}} expected-note {{using}}
@end @interface GSEbayCategory : NSObject <NSCoding> {
}
-- (int) categoryID;
+- (int) categoryID; // expected-note {{also found}}
- (GSEbayCategory *) parent;
- (GSEbayCategory*) subcategoryWithID:(int) inID;
@end @implementation GBCategoryChooserPanelController + (int) chooseCategoryIDFromCategories:(NSArray*) inCategories searchRequest:(GBSearchRequest*)inRequest parentWindow:(NSWindow*) inParent { // expected-warning {{incomplete implementation}}
return 0;
}
- (void) addCategory:(EBayCategoryType*)inCategory toRootTreeCategory:(NSMutableArray*)inRootTreeCategories {
- GSEbayCategory *category = [rootCategory subcategoryWithID:[[inCategory categoryID] intValue]];
+ GSEbayCategory *category = [rootCategory subcategoryWithID:[[inCategory categoryID] intValue]]; // expected-warning {{multiple methods named 'categoryID' found}}
if (rootCategory != category) {
GSEbayCategory *parent = category;
diff --git a/test/Analysis/retain-release-gc-only.m b/test/Analysis/retain-release-gc-only.m
index cbf00a27721d..ee1a6b4b782e 100644
--- a/test/Analysis/retain-release-gc-only.m
+++ b/test/Analysis/retain-release-gc-only.m
@@ -113,6 +113,7 @@ NSFastEnumerationState;
@end @interface NSAutoreleasePool : NSObject {
}
- (void)drain;
+- (id)init;
@end extern NSString * const NSBundleDidLoadNotification;
typedef double NSTimeInterval;
@interface NSDate : NSObject <NSCopying, NSCoding> - (NSTimeInterval)timeIntervalSinceReferenceDate;
diff --git a/test/Analysis/retain-release-path-notes-gc.m b/test/Analysis/retain-release-path-notes-gc.m
new file mode 100644
index 000000000000..21d314fa1541
--- /dev/null
+++ b/test/Analysis/retain-release-path-notes-gc.m
@@ -0,0 +1,74 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease -analyzer-store=basic -analyzer-output=text -fobjc-gc-only -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease -analyzer-store=region -analyzer-output=text -fobjc-gc-only -verify %s
+
+/***
+This file is for testing the path-sensitive notes for retain/release errors.
+Its goal is to have simple branch coverage of any path-based diagnostics,
+not to actually check all possible retain/release errors.
+
+This file is for notes that only appear in a GC-enabled analysis.
+Non-specific and ref-count-only notes should go in retain-release-path-notes.m.
+***/
+
+@interface NSObject
++ (id)alloc;
+- (id)init;
+- (void)dealloc;
+
+- (Class)class;
+
+- (id)retain;
+- (void)release;
+- (void)autorelease;
+@end
+
+@interface Foo : NSObject
+- (id)methodWithValue;
+@property(retain) id propertyValue;
+@end
+
+typedef struct CFType *CFTypeRef;
+CFTypeRef CFRetain(CFTypeRef);
+void CFRelease(CFTypeRef);
+
+id NSMakeCollectable(CFTypeRef);
+CFTypeRef CFMakeCollectable(CFTypeRef);
+
+CFTypeRef CFCreateSomething();
+CFTypeRef CFGetSomething();
+
+
+void creationViaCFCreate () {
+ CFTypeRef leaked = CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected}}
+ return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}}
+}
+
+void makeCollectable () {
+ CFTypeRef leaked = CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected}}
+ CFRetain(leaked); // expected-note{{Reference count incremented. The object now has a +2 retain count}}
+ CFMakeCollectable(leaked); // expected-note{{In GC mode a call to 'CFMakeCollectable' decrements an object's retain count and registers the object with the garbage collector. An object must have a 0 retain count to be garbage collected. After this call its retain count is +1.}}
+ NSMakeCollectable(leaked); // expected-note{{In GC mode a call to 'NSMakeCollectable' decrements an object's retain count and registers the object with the garbage collector. Since it now has a 0 retain count the object can be automatically collected by the garbage collector}}
+ CFRetain(leaked); // expected-note{{Reference count incremented. The object now has a +1 retain count. The object is not eligible for garbage collection until the retain count reaches 0 again.}}
+ return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}}
+}
+
+void retainReleaseIgnored () {
+ id object = [[NSObject alloc] init]; // expected-note{{Method returns an Objective-C object with a +0 retain count}}
+ [object retain]; // expected-note{{In GC mode the 'retain' message has no effect}}
+ [object release]; // expected-note{{In GC mode the 'release' message has no effect}}
+ [object autorelease]; // expected-note{{In GC mode an 'autorelease' has no effect}}
+ CFRelease((CFTypeRef)object); // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}} expected-note{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
+}
+
+@implementation Foo (FundamentalRuleUnderGC)
+- (id)getViolation {
+ id object = (id) CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected.}}
+ return object; // expected-note{{Object returned to caller as an owning reference (single retain count transferred to caller)}} expected-note{{Object leaked: object allocated and stored into 'object' and returned from method 'getViolation' is potentially leaked when using garbage collection. Callers of this method do not expect a returned object with a +1 retain count since they expect the object to be managed by the garbage collector}}
+}
+
+- (id)copyViolation {
+ id object = (id) CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected.}}
+ return object; // expected-note{{Object returned to caller as an owning reference (single retain count transferred to caller)}} expected-note{{Object leaked: object allocated and stored into 'object' and returned from method 'copyViolation' is potentially leaked when using garbage collection. Callers of this method do not expect a returned object with a +1 retain count since they expect the object to be managed by the garbage collector}}
+}
+@end
+
diff --git a/test/Analysis/retain-release-path-notes.m b/test/Analysis/retain-release-path-notes.m
new file mode 100644
index 000000000000..bac0afb3f7ab
--- /dev/null
+++ b/test/Analysis/retain-release-path-notes.m
@@ -0,0 +1,123 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease -analyzer-store=basic -analyzer-output=text -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease -analyzer-store=region -analyzer-output=text -verify %s
+
+/***
+This file is for testing the path-sensitive notes for retain/release errors.
+Its goal is to have simple branch coverage of any path-based diagnostics,
+not to actually check all possible retain/release errors.
+
+This file includes notes that only appear in a ref-counted analysis.
+GC-specific notes should go in retain-release-path-notes-gc.m.
+***/
+
+@interface NSObject
++ (id)alloc;
+- (id)init;
+- (void)dealloc;
+
+- (Class)class;
+
+- (id)retain;
+- (void)release;
+- (void)autorelease;
+@end
+
+@interface Foo : NSObject
+- (id)methodWithValue;
+@property(retain) id propertyValue;
+@end
+
+typedef struct CFType *CFTypeRef;
+CFTypeRef CFRetain(CFTypeRef);
+void CFRelease(CFTypeRef);
+
+id NSMakeCollectable(CFTypeRef);
+CFTypeRef CFMakeCollectable(CFTypeRef);
+
+CFTypeRef CFCreateSomething();
+CFTypeRef CFGetSomething();
+
+
+void creationViaAlloc () {
+ id leaked = [[NSObject alloc] init]; // expected-warning{{leak}} expected-note{{Method returns an Objective-C object with a +1 retain count}}
+ return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}}
+}
+
+void creationViaCFCreate () {
+ CFTypeRef leaked = CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count}}
+ return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}}
+}
+
+void acquisitionViaMethod (Foo *foo) {
+ id leaked = [foo methodWithValue]; // expected-warning{{leak}} expected-note{{Method returns an Objective-C object with a +0 retain count}}
+ [leaked retain]; // expected-note{{Reference count incremented. The object now has a +1 retain count}}
+ [leaked retain]; // expected-note{{Reference count incremented. The object now has a +2 retain count}}
+ [leaked release]; // expected-note{{Reference count decremented. The object now has a +1 retain count}}
+ return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}}
+}
+
+void acquisitionViaProperty (Foo *foo) {
+ id leaked = foo.propertyValue; // expected-warning{{leak}} expected-note{{Property returns an Objective-C object with a +0 retain count}}
+ [leaked retain]; // expected-note{{Reference count incremented. The object now has a +1 retain count}}
+ return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}}
+}
+
+void acquisitionViaCFFunction () {
+ CFTypeRef leaked = CFGetSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFGetSomething' returns a Core Foundation object with a +0 retain count}}
+ CFRetain(leaked); // expected-note{{Reference count incremented. The object now has a +1 retain count}}
+ return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}}
+}
+
+void explicitDealloc () {
+ id object = [[NSObject alloc] init]; // expected-note{{Method returns an Objective-C object with a +1 retain count}}
+ [object dealloc]; // expected-note{{Object released by directly sending the '-dealloc' message}}
+ [object class]; // expected-warning{{Reference-counted object is used after it is released}} // expected-note{{Reference-counted object is used after it is released}}
+}
+
+void implicitDealloc () {
+ id object = [[NSObject alloc] init]; // expected-note{{Method returns an Objective-C object with a +1 retain count}}
+ [object release]; // expected-note{{Object released}}
+ [object class]; // expected-warning{{Reference-counted object is used after it is released}} // expected-note{{Reference-counted object is used after it is released}}
+}
+
+void overAutorelease () {
+ id object = [[NSObject alloc] init]; // expected-note{{Method returns an Objective-C object with a +1 retain count}}
+ [object autorelease]; // expected-note{{Object sent -autorelease message}}
+ [object autorelease]; // expected-note{{Object sent -autorelease message}}
+ return; // expected-warning{{Object sent -autorelease too many times}} expected-note{{Object over-autoreleased: object was sent -autorelease 2 times but the object has a +1 retain count}}
+}
+
+void autoreleaseUnowned (Foo *foo) {
+ id object = foo.propertyValue; // expected-note{{Property returns an Objective-C object with a +0 retain count}}
+ [object autorelease]; // expected-note{{Object sent -autorelease message}}
+ return; // expected-warning{{Object sent -autorelease too many times}} expected-note{{Object over-autoreleased: object was sent -autorelease but the object has a +0 retain count}}
+}
+
+void makeCollectableIgnored () {
+ CFTypeRef leaked = CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count}}
+ CFMakeCollectable(leaked); // expected-note{{When GC is not enabled a call to 'CFMakeCollectable' has no effect on its argument}}
+ NSMakeCollectable(leaked); // expected-note{{When GC is not enabled a call to 'NSMakeCollectable' has no effect on its argument}}
+ return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}}
+}
+
+CFTypeRef CFCopyRuleViolation () {
+ CFTypeRef object = CFGetSomething(); // expected-note{{Call to function 'CFGetSomething' returns a Core Foundation object with a +0 retain counte}}
+ return object; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} expected-note{{Object returned to caller with a +0 retain count}} expected-note{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}}
+}
+
+CFTypeRef CFGetRuleViolation () {
+ CFTypeRef object = CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain counte}}
+ return object; // expected-note{{Object returned to caller as an owning reference (single retain count transferred to caller)}} expected-note{{Object leaked: object allocated and stored into 'object' is return from a function whose name ('CFGetRuleViolation') does not contain 'Copy' or 'Create'. This violates the naming convention rules given the Memory Management Guide for Core Foundation}}
+}
+
+@implementation Foo (FundamentalMemoryManagementRules)
+- (id)copyViolation {
+ id result = self.propertyValue; // expected-note{{Property returns an Objective-C object with a +0 retain count}}
+ return result; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} expected-note{{Object returned to caller with a +0 retain count}} expected-note{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}}
+}
+
+- (id)getViolation {
+ id result = [[Foo alloc] init]; // expected-warning{{leak}} expected-note{{Method returns an Objective-C object with a +1 retain count}}
+ return result; // expected-note{{Object returned to caller as an owning reference (single retain count transferred to caller)}} expected-note{{Object leaked: object allocated and stored into 'result' is returned from a method whose name ('getViolation') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'. This violates the naming convention rules given in the Memory Management Guide for Cocoa}}
+}
+@end
diff --git a/test/Analysis/retain-release.m b/test/Analysis/retain-release.m
index 7af14f129c3f..71ae756cf045 100644
--- a/test/Analysis/retain-release.m
+++ b/test/Analysis/retain-release.m
@@ -116,6 +116,7 @@ typedef struct _NSZone NSZone;
- (id)retain;
- (oneway void)release;
- (id)autorelease;
+- (id)init;
@end @protocol NSCopying - (id)copyWithZone:(NSZone *)zone;
@end @protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone;
@end @protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder;
@@ -517,7 +518,7 @@ void f17(int x, CFTypeRef p) {
@implementation TestReturnNotOwnedWhenExpectedOwned
- (NSString*)newString {
NSString *s = [NSString stringWithUTF8String:"hello"];
- return s; // expected-warning{{Object with +0 retain counts returned to caller where a +1 (owning) retain count is expected}}
+ return s; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}}
}
@end
@@ -735,7 +736,7 @@ typedef CFTypeRef OtherRef;
- (id)initReturningNewClassBad2 {
[self release];
self = [[RDar6320065Subclass alloc] init];
- return [self autorelease]; // expected-warning{{Object with +0 retain counts returned to caller where a +1 (owning) retain count is expected}}
+ return [self autorelease]; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}}
}
@end
@@ -1302,7 +1303,7 @@ CFDateRef returnsRetainedCFDate() {
}
- (CFDateRef) newCFRetainedAsCFNoAttr {
- return (CFDateRef)[(id)[self returnsCFRetainedAsCF] autorelease]; // expected-warning{{Object with +0 retain counts returned to caller where a +1 (owning) retain count is expected}}
+ return (CFDateRef)[(id)[self returnsCFRetainedAsCF] autorelease]; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}}
}
- (NSDate*) alsoReturnsRetained {
@@ -1445,7 +1446,7 @@ static void rdar_8724287(CFErrorRef error)
while (error_to_dump != ((void*)0)) {
CFDictionaryRef info;
- info = CFErrorCopyUserInfo(error_to_dump); // expected-warning{{Potential leak of an object allocated on line 1448 and stored into 'info'}}
+ info = CFErrorCopyUserInfo(error_to_dump); // expected-warning{{Potential leak of an object allocated on line 1449 and stored into 'info'}}
if (info != ((void*)0)) {
}
@@ -1461,3 +1462,81 @@ extern void rdar_9234108_helper(void *key, void * CF_CONSUMED value);
void rdar_9234108() {
rdar_9234108_helper(0, CFStringCreate());
}
+
+// <rdar://problem/9726279> - Make sure that objc_method_family works
+// to override naming conventions.
+struct TwoDoubles {
+ double one;
+ double two;
+};
+typedef struct TwoDoubles TwoDoubles;
+
+@interface NSValue (Mine)
+- (id)_prefix_initWithTwoDoubles:(TwoDoubles)twoDoubles __attribute__((objc_method_family(init)));
+@end
+
+@implementation NSValue (Mine)
+- (id)_prefix_initWithTwoDoubles:(TwoDoubles)twoDoubles
+{
+ return [self init];
+}
+@end
+
+void rdar9726279() {
+ TwoDoubles twoDoubles = { 0.0, 0.0 };
+ NSValue *value = [[NSValue alloc] _prefix_initWithTwoDoubles:twoDoubles];
+ [value release];
+}
+
+// <rdar://problem/9732321>
+// Test camelcase support for CF conventions. While Core Foundation APIs
+// don't use camel casing, other code is allowed to use it.
+CFArrayRef camelcase_create_1() {
+ return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning
+}
+
+CFArrayRef camelcase_createno() {
+ return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // expected-warning {{leak}}
+}
+
+CFArrayRef camelcase_copy() {
+ return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning
+}
+
+CFArrayRef camelcase_copying() {
+ return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // expected-warning {{leak}}
+}
+
+CFArrayRef copyCamelCase() {
+ return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning
+}
+
+CFArrayRef __copyCamelCase() {
+ return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning
+}
+
+CFArrayRef __createCamelCase() {
+ return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning
+}
+
+CFArrayRef camel_create() {
+ return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning
+}
+
+
+CFArrayRef camel_creat() {
+ return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // expected-warning {{leak}}
+}
+
+CFArrayRef camel_copy() {
+ return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning
+}
+
+CFArrayRef camel_copyMachine() {
+ return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning
+}
+
+CFArrayRef camel_copymachine() {
+ return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // expected-warning {{leak}}
+}
+
diff --git a/test/Analysis/retain-release.mm b/test/Analysis/retain-release.mm
index 0faeb1a2a300..bdc3dc03964a 100644
--- a/test/Analysis/retain-release.mm
+++ b/test/Analysis/retain-release.mm
@@ -121,6 +121,7 @@ typedef struct _NSZone NSZone;
+ (id)allocWithZone:(NSZone *)zone;
+ (id)alloc;
- (void)dealloc;
+- (id)init;
@end
@interface NSObject (NSCoderMethods)
- (id)awakeAfterUsingCoder:(NSCoder *)aDecoder;
diff --git a/test/Analysis/string-fail.c b/test/Analysis/string-fail.c
new file mode 100644
index 000000000000..64ac504d6d80
--- /dev/null
+++ b/test/Analysis/string-fail.c
@@ -0,0 +1,113 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.experimental.CString,deadcode.experimental.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,unix.experimental.CString,deadcode.experimental.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
+// XFAIL: *
+
+// This file is for tests that may eventually go into string.c, or may be
+// deleted outright. At one point these tests passed, but only because we
+// weren't correctly modelling the behavior of the relevant string functions.
+// The tests aren't incorrect, but require the analyzer to be smarter about
+// conjured values than it currently is.
+
+//===----------------------------------------------------------------------===
+// Declarations
+//===----------------------------------------------------------------------===
+
+// Some functions are so similar to each other that they follow the same code
+// path, such as memcpy and __memcpy_chk, or memcmp and bcmp. If VARIANT is
+// defined, make sure to use the variants instead to make sure they are still
+// checked by the analyzer.
+
+// Some functions are implemented as builtins. These should be #defined as
+// BUILTIN(f), which will prepend "__builtin_" if USE_BUILTINS is defined.
+
+// Functions that have variants and are also available as builtins should be
+// declared carefully! See memcpy() for an example.
+
+#ifdef USE_BUILTINS
+# define BUILTIN(f) __builtin_ ## f
+#else /* USE_BUILTINS */
+# define BUILTIN(f) f
+#endif /* USE_BUILTINS */
+
+#define NULL 0
+typedef typeof(sizeof(int)) size_t;
+
+
+//===----------------------------------------------------------------------===
+// strnlen()
+//===----------------------------------------------------------------------===
+
+#define strnlen BUILTIN(strnlen)
+size_t strnlen(const char *s, size_t maxlen);
+
+void strnlen_liveness(const char *x) {
+ if (strnlen(x, 10) < 5)
+ return;
+ if (strnlen(x, 10) < 5)
+ (void)*(char*)0; // no-warning
+}
+
+void strnlen_subregion() {
+ struct two_stringsn { char a[2], b[2]; };
+ extern void use_two_stringsn(struct two_stringsn *);
+
+ struct two_stringsn z;
+ use_two_stringsn(&z);
+
+ size_t a = strnlen(z.a, 10);
+ z.b[0] = 5;
+ size_t b = strnlen(z.a, 10);
+ if (a == 0 && b != 0)
+ (void)*(char*)0; // expected-warning{{never executed}}
+
+ use_two_stringsn(&z);
+
+ size_t c = strnlen(z.a, 10);
+ if (a == 0 && c != 0)
+ (void)*(char*)0; // expected-warning{{null}}
+}
+
+extern void use_stringn(char *);
+void strnlen_argument(char *x) {
+ size_t a = strnlen(x, 10);
+ size_t b = strnlen(x, 10);
+ if (a == 0 && b != 0)
+ (void)*(char*)0; // expected-warning{{never executed}}
+
+ use_stringn(x);
+
+ size_t c = strnlen(x, 10);
+ if (a == 0 && c != 0)
+ (void)*(char*)0; // expected-warning{{null}}
+}
+
+extern char global_strn[];
+void strnlen_global() {
+ size_t a = strnlen(global_strn, 10);
+ size_t b = strnlen(global_strn, 10);
+ if (a == 0 && b != 0)
+ (void)*(char*)0; // expected-warning{{never executed}}
+
+ // Call a function with unknown effects, which should invalidate globals.
+ use_stringn(0);
+
+ size_t c = strnlen(global_strn, 10);
+ if (a == 0 && c != 0)
+ (void)*(char*)0; // expected-warning{{null}}
+}
+
+void strnlen_indirect(char *x) {
+ size_t a = strnlen(x, 10);
+ char *p = x;
+ char **p2 = &p;
+ size_t b = strnlen(x, 10);
+ if (a == 0 && b != 0)
+ (void)*(char*)0; // expected-warning{{never executed}}
+
+ extern void use_stringn_ptr(char*const*);
+ use_stringn_ptr(p2);
+
+ size_t c = strnlen(x, 10);
+ if (a == 0 && c != 0)
+ (void)*(char*)0; // expected-warning{{null}}
+}
diff --git a/test/Analysis/string.c b/test/Analysis/string.c
index e6baf51c474c..dc97e1a119e0 100644
--- a/test/Analysis/string.c
+++ b/test/Analysis/string.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.experimental.CString,deadcode.experimental.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
-// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,cplusplus.experimental.CString,deadcode.experimental.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
-// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-checker=core,cplusplus.experimental.CString,deadcode.experimental.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
-// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=core,cplusplus.experimental.CString,deadcode.experimental.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.experimental.CString,deadcode.experimental.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,unix.experimental.CString,deadcode.experimental.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-checker=core,unix.experimental.CString,deadcode.experimental.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=core,unix.experimental.CString,deadcode.experimental.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
//===----------------------------------------------------------------------===
// Declarations
@@ -55,16 +55,16 @@ void strlen_constant2(char x) {
}
size_t strlen_null() {
- return strlen(0); // expected-warning{{Null pointer argument in call to byte string function}}
+ return strlen(0); // expected-warning{{Null pointer argument in call to string length function}}
}
size_t strlen_fn() {
- return strlen((char*)&strlen_fn); // expected-warning{{Argument to byte string function is the address of the function 'strlen_fn', which is not a null-terminated string}}
+ return strlen((char*)&strlen_fn); // expected-warning{{Argument to string length function is the address of the function 'strlen_fn', which is not a null-terminated string}}
}
size_t strlen_nonloc() {
label:
- return strlen((char*)&&label); // expected-warning{{Argument to byte string function is the address of the label 'label', which is not a null-terminated string}}
+ return strlen((char*)&&label); // expected-warning{{Argument to string length function is the address of the label 'label', which is not a null-terminated string}}
}
void strlen_subregion() {
@@ -143,24 +143,23 @@ void strlen_liveness(const char *x) {
// strnlen()
//===----------------------------------------------------------------------===
-#define strnlen BUILTIN(strnlen)
size_t strnlen(const char *s, size_t maxlen);
void strnlen_constant0() {
if (strnlen("123", 10) != 3)
- (void)*(char*)0; // no-warning
+ (void)*(char*)0; // expected-warning{{never executed}}
}
void strnlen_constant1() {
const char *a = "123";
if (strnlen(a, 10) != 3)
- (void)*(char*)0; // no-warning
+ (void)*(char*)0; // expected-warning{{never executed}}
}
void strnlen_constant2(char x) {
char a[] = "123";
if (strnlen(a, 10) != 3)
- (void)*(char*)0; // no-warning
+ (void)*(char*)0; // expected-warning{{never executed}}
a[0] = x;
if (strnlen(a, 10) != 3)
(void)*(char*)0; // expected-warning{{null}}
@@ -168,107 +167,90 @@ void strnlen_constant2(char x) {
void strnlen_constant4() {
if (strnlen("123456", 3) != 3)
- (void)*(char*)0; // no-warning
+ (void)*(char*)0; // expected-warning{{never executed}}
}
void strnlen_constant5() {
const char *a = "123456";
if (strnlen(a, 3) != 3)
- (void)*(char*)0; // no-warning
+ (void)*(char*)0; // expected-warning{{never executed}}
}
void strnlen_constant6(char x) {
char a[] = "123456";
if (strnlen(a, 3) != 3)
- (void)*(char*)0; // no-warning
+ (void)*(char*)0; // expected-warning{{never executed}}
a[0] = x;
if (strnlen(a, 3) != 3)
(void)*(char*)0; // expected-warning{{null}}
}
size_t strnlen_null() {
- return strnlen(0, 3); // expected-warning{{Null pointer argument in call to byte string function}}
+ return strnlen(0, 3); // expected-warning{{Null pointer argument in call to string length function}}
}
size_t strnlen_fn() {
- return strnlen((char*)&strlen_fn, 3); // expected-warning{{Argument to byte string function is the address of the function 'strlen_fn', which is not a null-terminated string}}
+ return strnlen((char*)&strlen_fn, 3); // expected-warning{{Argument to string length function is the address of the function 'strlen_fn', which is not a null-terminated string}}
}
size_t strnlen_nonloc() {
label:
- return strnlen((char*)&&label, 3); // expected-warning{{Argument to byte string function is the address of the label 'label', which is not a null-terminated string}}
+ return strnlen((char*)&&label, 3); // expected-warning{{Argument to string length function is the address of the label 'label', which is not a null-terminated string}}
}
-void strnlen_subregion() {
- struct two_stringsn { char a[2], b[2]; };
- extern void use_two_stringsn(struct two_stringsn *);
-
- struct two_stringsn z;
- use_two_stringsn(&z);
-
- size_t a = strnlen(z.a, 10);
- z.b[0] = 5;
- size_t b = strnlen(z.a, 10);
- if (a == 0 && b != 0)
+void strnlen_zero() {
+ if (strnlen("abc", 0) != 0)
(void)*(char*)0; // expected-warning{{never executed}}
+ if (strnlen(NULL, 0) != 0) // no-warning
+ (void)*(char*)0; // no-warning
+}
+
+size_t strnlen_compound_literal() {
+ // This used to crash because we don't model the string lengths of
+ // compound literals.
+ return strnlen((char[]) { 'a', 'b', 0 }, 1);
+}
- use_two_stringsn(&z);
+size_t strnlen_unknown_limit(float f) {
+ // This used to crash because we don't model the integer values of floats.
+ return strnlen("abc", (int)f);
+}
- size_t c = strnlen(z.a, 10);
- if (a == 0 && c != 0)
+void strnlen_is_not_strlen(char *x) {
+ if (strnlen(x, 10) != strlen(x))
(void)*(char*)0; // expected-warning{{null}}
}
-extern void use_stringn(char *);
-void strnlen_argument(char *x) {
- size_t a = strnlen(x, 10);
- size_t b = strnlen(x, 10);
- if (a == 0 && b != 0)
+void strnlen_at_limit(char *x) {
+ size_t len = strnlen(x, 10);
+ if (len > 10)
(void)*(char*)0; // expected-warning{{never executed}}
-
- use_stringn(x);
-
- size_t c = strnlen(x, 10);
- if (a == 0 && c != 0)
- (void)*(char*)0; // expected-warning{{null}}
+ if (len == 10)
+ (void)*(char*)0; // expected-warning{{null}}
}
-extern char global_strn[];
-void strnlen_global() {
- size_t a = strnlen(global_strn, 10);
- size_t b = strnlen(global_strn, 10);
- if (a == 0 && b != 0)
+void strnlen_less_than_limit(char *x) {
+ size_t len = strnlen(x, 10);
+ if (len > 10)
(void)*(char*)0; // expected-warning{{never executed}}
-
- // Call a function with unknown effects, which should invalidate globals.
- use_stringn(0);
-
- size_t c = strnlen(global_str, 10);
- if (a == 0 && c != 0)
- (void)*(char*)0; // expected-warning{{null}}
+ if (len < 10)
+ (void)*(char*)0; // expected-warning{{null}}
}
-void strnlen_indirect(char *x) {
- size_t a = strnlen(x, 10);
- char *p = x;
- char **p2 = &p;
- size_t b = strnlen(x, 10);
- if (a == 0 && b != 0)
+void strnlen_at_actual(size_t limit) {
+ size_t len = strnlen("abc", limit);
+ if (len > 3)
(void)*(char*)0; // expected-warning{{never executed}}
-
- extern void use_stringn_ptr(char*const*);
- use_stringn_ptr(p2);
-
- size_t c = strnlen(x, 10);
- if (a == 0 && c != 0)
+ if (len == 3)
(void)*(char*)0; // expected-warning{{null}}
}
-void strnlen_liveness(const char *x) {
- if (strnlen(x, 10) < 5)
- return;
- if (strnlen(x, 10) < 5)
- (void)*(char*)0; // no-warning
+void strnlen_less_than_actual(size_t limit) {
+ size_t len = strnlen("abc", limit);
+ if (len > 3)
+ (void)*(char*)0; // expected-warning{{never executed}}
+ if (len < 3)
+ (void)*(char*)0; // expected-warning{{null}}
}
//===----------------------------------------------------------------------===
@@ -291,15 +273,15 @@ char *strcpy(char *restrict s1, const char *restrict s2);
void strcpy_null_dst(char *x) {
- strcpy(NULL, x); // expected-warning{{Null pointer argument in call to byte string function}}
+ strcpy(NULL, x); // expected-warning{{Null pointer argument in call to string copy function}}
}
void strcpy_null_src(char *x) {
- strcpy(x, NULL); // expected-warning{{Null pointer argument in call to byte string function}}
+ strcpy(x, NULL); // expected-warning{{Null pointer argument in call to string copy function}}
}
void strcpy_fn(char *x) {
- strcpy(x, (char*)&strcpy_fn); // expected-warning{{Argument to byte string function is the address of the function 'strcpy_fn', which is not a null-terminated string}}
+ strcpy(x, (char*)&strcpy_fn); // expected-warning{{Argument to string copy function is the address of the function 'strcpy_fn', which is not a null-terminated string}}
}
void strcpy_effects(char *x, char *y) {
@@ -318,7 +300,7 @@ void strcpy_effects(char *x, char *y) {
void strcpy_overflow(char *y) {
char x[4];
if (strlen(y) == 4)
- strcpy(x, y); // expected-warning{{Byte string function overflows destination buffer}}
+ strcpy(x, y); // expected-warning{{String copy function overflows destination buffer}}
}
void strcpy_no_overflow(char *y) {
@@ -362,7 +344,7 @@ void stpcpy_effect(char *x, char *y) {
void stpcpy_overflow(char *y) {
char x[4];
if (strlen(y) == 4)
- stpcpy(x, y); // expected-warning{{Byte string function overflows destination buffer}}
+ stpcpy(x, y); // expected-warning{{String copy function overflows destination buffer}}
}
void stpcpy_no_overflow(char *y) {
@@ -391,15 +373,15 @@ char *strcat(char *restrict s1, const char *restrict s2);
void strcat_null_dst(char *x) {
- strcat(NULL, x); // expected-warning{{Null pointer argument in call to byte string function}}
+ strcat(NULL, x); // expected-warning{{Null pointer argument in call to string copy function}}
}
void strcat_null_src(char *x) {
- strcat(x, NULL); // expected-warning{{Null pointer argument in call to byte string function}}
+ strcat(x, NULL); // expected-warning{{Null pointer argument in call to string copy function}}
}
void strcat_fn(char *x) {
- strcat(x, (char*)&strcat_fn); // expected-warning{{Argument to byte string function is the address of the function 'strcat_fn', which is not a null-terminated string}}
+ strcat(x, (char*)&strcat_fn); // expected-warning{{Argument to string copy function is the address of the function 'strcat_fn', which is not a null-terminated string}}
}
void strcat_effects(char *y) {
@@ -415,27 +397,24 @@ void strcat_effects(char *y) {
if ((int)strlen(x) != (orig_len + strlen(y)))
(void)*(char*)0; // no-warning
-
- if (a != x[0])
- (void)*(char*)0; // expected-warning{{null}}
}
void strcat_overflow_0(char *y) {
char x[4] = "12";
if (strlen(y) == 4)
- strcat(x, y); // expected-warning{{Byte string function overflows destination buffer}}
+ strcat(x, y); // expected-warning{{String copy function overflows destination buffer}}
}
void strcat_overflow_1(char *y) {
char x[4] = "12";
if (strlen(y) == 3)
- strcat(x, y); // expected-warning{{Byte string function overflows destination buffer}}
+ strcat(x, y); // expected-warning{{String copy function overflows destination buffer}}
}
void strcat_overflow_2(char *y) {
char x[4] = "12";
if (strlen(y) == 2)
- strcat(x, y); // expected-warning{{Byte string function overflows destination buffer}}
+ strcat(x, y); // expected-warning{{String copy function overflows destination buffer}}
}
void strcat_no_overflow(char *y) {
@@ -444,6 +423,136 @@ void strcat_no_overflow(char *y) {
strcat(x, y); // no-warning
}
+void strcat_symbolic_dst_length(char *dst) {
+ strcat(dst, "1234");
+ if (strlen(dst) < 4)
+ (void)*(char*)0; // no-warning
+}
+
+void strcat_symbolic_src_length(char *src) {
+ char dst[8] = "1234";
+ strcat(dst, src);
+ if (strlen(dst) < 4)
+ (void)*(char*)0; // no-warning
+}
+
+void strcat_unknown_src_length(char *src, int offset) {
+ char dst[8] = "1234";
+ strcat(dst, &src[offset]);
+ if (strlen(dst) < 4)
+ (void)*(char*)0; // no-warning
+}
+
+// There is no strcat_unknown_dst_length because if we can't get a symbolic
+// length for the "before" strlen, we won't be able to set one for "after".
+
+void strcat_too_big(char *dst, char *src) {
+ if (strlen(dst) != (((size_t)0) - 2))
+ return;
+ if (strlen(src) != 2)
+ return;
+ strcat(dst, src); // expected-warning{{This expression will create a string whose length is too big to be represented as a size_t}}
+}
+
+
+//===----------------------------------------------------------------------===
+// strncpy()
+//===----------------------------------------------------------------------===
+
+#ifdef VARIANT
+
+#define __strncpy_chk BUILTIN(__strncpy_chk)
+char *__strncpy_chk(char *restrict s1, const char *restrict s2, size_t n, size_t destlen);
+
+#define strncpy(a,b,n) __strncpy_chk(a,b,n,(size_t)-1)
+
+#else /* VARIANT */
+
+#define strncpy BUILTIN(strncpy)
+char *strncpy(char *restrict s1, const char *restrict s2, size_t n);
+
+#endif /* VARIANT */
+
+
+void strncpy_null_dst(char *x) {
+ strncpy(NULL, x, 5); // expected-warning{{Null pointer argument in call to string copy function}}
+}
+
+void strncpy_null_src(char *x) {
+ strncpy(x, NULL, 5); // expected-warning{{Null pointer argument in call to string copy function}}
+}
+
+void strncpy_fn(char *x) {
+ strncpy(x, (char*)&strcpy_fn, 5); // expected-warning{{Argument to string copy function is the address of the function 'strcpy_fn', which is not a null-terminated string}}
+}
+
+void strncpy_effects(char *x, char *y) {
+ char a = x[0];
+
+ if (strncpy(x, y, 5) != x)
+ (void)*(char*)0; // no-warning
+
+ if (strlen(x) != strlen(y))
+ (void)*(char*)0; // expected-warning{{null}}
+
+ if (a != x[0])
+ (void)*(char*)0; // expected-warning{{null}}
+}
+
+void strncpy_overflow(char *y) {
+ char x[4];
+ if (strlen(y) == 4)
+ strncpy(x, y, 5); // expected-warning{{Size argument is greater than the length of the destination buffer}}
+}
+
+void strncpy_no_overflow(char *y) {
+ char x[4];
+ if (strlen(y) == 3)
+ strncpy(x, y, 5); // expected-warning{{Size argument is greater than the length of the destination buffer}}
+}
+
+void strncpy_no_overflow2(char *y, int n) {
+ if (n <= 4)
+ return;
+
+ char x[4];
+ if (strlen(y) == 3)
+ strncpy(x, y, n); // expected-warning{{Size argument is greater than the length of the destination buffer}}
+}
+
+void strncpy_truncate(char *y) {
+ char x[4];
+ if (strlen(y) == 4)
+ strncpy(x, y, 3); // no-warning
+}
+
+void strncpy_no_truncate(char *y) {
+ char x[4];
+ if (strlen(y) == 3)
+ strncpy(x, y, 3); // no-warning
+}
+
+void strncpy_exactly_matching_buffer(char *y) {
+ char x[4];
+ strncpy(x, y, 4); // no-warning
+
+ // strncpy does not null-terminate, so we have no idea what the strlen is
+ // after this.
+ if (strlen(x) > 4)
+ (void)*(int*)0; // expected-warning{{null}}
+}
+
+void strncpy_exactly_matching_buffer2(char *y) {
+ if (strlen(y) >= 4)
+ return;
+
+ char x[4];
+ strncpy(x, y, 4); // no-warning
+
+ // This time, we know that y fits in x anyway.
+ if (strlen(x) > 3)
+ (void)*(int*)0; // no-warning
+}
//===----------------------------------------------------------------------===
// strncat()
@@ -465,15 +574,15 @@ char *strncat(char *restrict s1, const char *restrict s2, size_t n);
void strncat_null_dst(char *x) {
- strncat(NULL, x, 4); // expected-warning{{Null pointer argument in call to byte string function}}
+ strncat(NULL, x, 4); // expected-warning{{Null pointer argument in call to string copy function}}
}
void strncat_null_src(char *x) {
- strncat(x, NULL, 4); // expected-warning{{Null pointer argument in call to byte string function}}
+ strncat(x, NULL, 4); // expected-warning{{Null pointer argument in call to string copy function}}
}
void strncat_fn(char *x) {
- strncat(x, (char*)&strncat_fn, 4); // expected-warning{{Argument to byte string function is the address of the function 'strncat_fn', which is not a null-terminated string}}
+ strncat(x, (char*)&strncat_fn, 4); // expected-warning{{Argument to string copy function is the address of the function 'strncat_fn', which is not a null-terminated string}}
}
void strncat_effects(char *y) {
@@ -489,33 +598,30 @@ void strncat_effects(char *y) {
if (strlen(x) != orig_len + strlen(y))
(void)*(char*)0; // no-warning
-
- if (a != x[0])
- (void)*(char*)0; // expected-warning{{null}}
}
void strncat_overflow_0(char *y) {
char x[4] = "12";
if (strlen(y) == 4)
- strncat(x, y, strlen(y)); // expected-warning{{Byte string function overflows destination buffer}}
+ strncat(x, y, strlen(y)); // expected-warning{{Size argument is greater than the free space in the destination buffer}}
}
void strncat_overflow_1(char *y) {
char x[4] = "12";
if (strlen(y) == 3)
- strncat(x, y, strlen(y)); // expected-warning{{Byte string function overflows destination buffer}}
+ strncat(x, y, strlen(y)); // expected-warning{{Size argument is greater than the free space in the destination buffer}}
}
void strncat_overflow_2(char *y) {
char x[4] = "12";
if (strlen(y) == 2)
- strncat(x, y, strlen(y)); // expected-warning{{Byte string function overflows destination buffer}}
+ strncat(x, y, strlen(y)); // expected-warning{{Size argument is greater than the free space in the destination buffer}}
}
void strncat_overflow_3(char *y) {
char x[4] = "12";
if (strlen(y) == 4)
- strncat(x, y, 2); // expected-warning{{Byte string function overflows destination buffer}}
+ strncat(x, y, 2); // expected-warning{{Size argument is greater than the free space in the destination buffer}}
}
void strncat_no_overflow_1(char *y) {
char x[5] = "12";
@@ -529,12 +635,69 @@ void strncat_no_overflow_2(char *y) {
strncat(x, y, 1); // no-warning
}
+void strncat_symbolic_dst_length(char *dst) {
+ strncat(dst, "1234", 5);
+ if (strlen(dst) < 4)
+ (void)*(char*)0; // no-warning
+}
+
+void strncat_symbolic_src_length(char *src) {
+ char dst[8] = "1234";
+ strncat(dst, src, 3);
+ if (strlen(dst) < 4)
+ (void)*(char*)0; // no-warning
+
+ char dst2[8] = "1234";
+ strncat(dst2, src, 4); // expected-warning{{Size argument is greater than the free space in the destination buffer}}
+}
+
+void strncat_unknown_src_length(char *src, int offset) {
+ char dst[8] = "1234";
+ strncat(dst, &src[offset], 3);
+ if (strlen(dst) < 4)
+ (void)*(char*)0; // no-warning
+
+ char dst2[8] = "1234";
+ strncat(dst2, &src[offset], 4); // expected-warning{{Size argument is greater than the free space in the destination buffer}}
+}
+
+// There is no strncat_unknown_dst_length because if we can't get a symbolic
+// length for the "before" strlen, we won't be able to set one for "after".
+
+void strncat_symbolic_limit(unsigned limit) {
+ char dst[6] = "1234";
+ char src[] = "567";
+ strncat(dst, src, limit); // no-warning
+ if (strlen(dst) < 4)
+ (void)*(char*)0; // no-warning
+ if (strlen(dst) == 4)
+ (void)*(char*)0; // expected-warning{{null}}
+}
+
+void strncat_unknown_limit(float limit) {
+ char dst[6] = "1234";
+ char src[] = "567";
+ strncat(dst, src, (size_t)limit); // no-warning
+ if (strlen(dst) < 4)
+ (void)*(char*)0; // no-warning
+ if (strlen(dst) == 4)
+ (void)*(char*)0; // expected-warning{{null}}
+}
+
+void strncat_too_big(char *dst, char *src) {
+ if (strlen(dst) != (((size_t)0) - 2))
+ return;
+ if (strlen(src) != 2)
+ return;
+ strncat(dst, src, 2); // expected-warning{{This expression will create a string whose length is too big to be represented as a size_t}}
+}
+
//===----------------------------------------------------------------------===
// strcmp()
//===----------------------------------------------------------------------===
#define strcmp BUILTIN(strcmp)
-int strcmp(const char *restrict s1, const char *restrict s2);
+int strcmp(const char * s1, const char * s2);
void strcmp_constant0() {
if (strcmp("123", "123") != 0)
@@ -577,13 +740,13 @@ void strcmp_2() {
void strcmp_null_0() {
char *x = NULL;
char *y = "123";
- strcmp(x, y); // expected-warning{{Null pointer argument in call to byte string function}}
+ strcmp(x, y); // expected-warning{{Null pointer argument in call to string comparison function}}
}
void strcmp_null_1() {
char *x = "123";
char *y = NULL;
- strcmp(x, y); // expected-warning{{Null pointer argument in call to byte string function}}
+ strcmp(x, y); // expected-warning{{Null pointer argument in call to string comparison function}}
}
void strcmp_diff_length_0() {
@@ -614,12 +777,22 @@ void strcmp_diff_length_3() {
(void)*(char*)0; // no-warning
}
+void strcmp_embedded_null () {
+ if (strcmp("\0z", "\0y") != 0)
+ (void)*(char*)0; // no-warning
+}
+
+void strcmp_unknown_arg (char *unknown) {
+ if (strcmp(unknown, unknown) != 0)
+ (void)*(char*)0; // no-warning
+}
+
//===----------------------------------------------------------------------===
// strncmp()
//===----------------------------------------------------------------------===
#define strncmp BUILTIN(strncmp)
-int strncmp(const char *restrict s1, const char *restrict s2, size_t n);
+int strncmp(const char *s1, const char *s2, size_t n);
void strncmp_constant0() {
if (strncmp("123", "123", 3) != 0)
@@ -662,13 +835,13 @@ void strncmp_2() {
void strncmp_null_0() {
char *x = NULL;
char *y = "123";
- strncmp(x, y, 3); // expected-warning{{Null pointer argument in call to byte string function}}
+ strncmp(x, y, 3); // expected-warning{{Null pointer argument in call to string comparison function}}
}
void strncmp_null_1() {
char *x = "123";
char *y = NULL;
- strncmp(x, y, 3); // expected-warning{{Null pointer argument in call to byte string function}}
+ strncmp(x, y, 3); // expected-warning{{Null pointer argument in call to string comparison function}}
}
void strncmp_diff_length_0() {
@@ -720,12 +893,17 @@ void strncmp_diff_length_6() {
(void)*(char*)0; // no-warning
}
+void strncmp_embedded_null () {
+ if (strncmp("ab\0zz", "ab\0yy", 4) != 0)
+ (void)*(char*)0; // no-warning
+}
+
//===----------------------------------------------------------------------===
// strcasecmp()
//===----------------------------------------------------------------------===
#define strcasecmp BUILTIN(strcasecmp)
-int strcasecmp(const char *restrict s1, const char *restrict s2);
+int strcasecmp(const char *s1, const char *s2);
void strcasecmp_constant0() {
if (strcasecmp("abc", "Abc") != 0)
@@ -768,13 +946,13 @@ void strcasecmp_2() {
void strcasecmp_null_0() {
char *x = NULL;
char *y = "123";
- strcasecmp(x, y); // expected-warning{{Null pointer argument in call to byte string function}}
+ strcasecmp(x, y); // expected-warning{{Null pointer argument in call to string comparison function}}
}
void strcasecmp_null_1() {
char *x = "123";
char *y = NULL;
- strcasecmp(x, y); // expected-warning{{Null pointer argument in call to byte string function}}
+ strcasecmp(x, y); // expected-warning{{Null pointer argument in call to string comparison function}}
}
void strcasecmp_diff_length_0() {
@@ -805,12 +983,17 @@ void strcasecmp_diff_length_3() {
(void)*(char*)0; // no-warning
}
+void strcasecmp_embedded_null () {
+ if (strcasecmp("ab\0zz", "ab\0yy") != 0)
+ (void)*(char*)0; // no-warning
+}
+
//===----------------------------------------------------------------------===
// strncasecmp()
//===----------------------------------------------------------------------===
#define strncasecmp BUILTIN(strncasecmp)
-int strncasecmp(const char *restrict s1, const char *restrict s2, size_t n);
+int strncasecmp(const char *s1, const char *s2, size_t n);
void strncasecmp_constant0() {
if (strncasecmp("abc", "Abc", 3) != 0)
@@ -853,13 +1036,13 @@ void strncasecmp_2() {
void strncasecmp_null_0() {
char *x = NULL;
char *y = "123";
- strncasecmp(x, y, 3); // expected-warning{{Null pointer argument in call to byte string function}}
+ strncasecmp(x, y, 3); // expected-warning{{Null pointer argument in call to string comparison function}}
}
void strncasecmp_null_1() {
char *x = "123";
char *y = NULL;
- strncasecmp(x, y, 3); // expected-warning{{Null pointer argument in call to byte string function}}
+ strncasecmp(x, y, 3); // expected-warning{{Null pointer argument in call to string comparison function}}
}
void strncasecmp_diff_length_0() {
@@ -910,3 +1093,8 @@ void strncasecmp_diff_length_6() {
if (strncasecmp(x, y, 3) != 1)
(void)*(char*)0; // no-warning
}
+
+void strncasecmp_embedded_null () {
+ if (strncasecmp("ab\0zz", "ab\0yy", 4) != 0)
+ (void)*(char*)0; // no-warning
+}
diff --git a/test/Analysis/uninit-ps-rdar6145427.m b/test/Analysis/uninit-ps-rdar6145427.m
index f1794068d5e1..f4df91396a84 100644
--- a/test/Analysis/uninit-ps-rdar6145427.m
+++ b/test/Analysis/uninit-ps-rdar6145427.m
@@ -11,7 +11,10 @@ typedef struct _NSZone NSZone;
@protocol NSObject - (BOOL)isEqual:(id)object; @end
@protocol NSCopying - (id)copyWithZone:(NSZone *)zone; @end
@protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; @end
-@interface NSObject <NSObject> {} + (id)alloc; @end
+@interface NSObject <NSObject> {}
++ (id)alloc;
+- (id)init;
+@end
extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone);
@interface NSValue : NSObject <NSCopying, NSCoding> - (void)getValue:(void *)value; @end
@class NSString, NSData;
diff --git a/test/Analysis/uninit-vals-ps-region.m b/test/Analysis/uninit-vals-ps-region.m
index 1700f54dbfb0..c62818a12e0d 100644
--- a/test/Analysis/uninit-vals-ps-region.m
+++ b/test/Analysis/uninit-vals-ps-region.m
@@ -67,3 +67,12 @@ void rdar_7780304() {
b.x |= 1; // expected-warning{{The left expression of the compound assignment is an uninitialized value. The computed value will also be garbage}}
}
+
+// The flip side of PR10163 -- float arrays that are actually uninitialized
+// (The main test is in uninit-vals.m)
+void test_PR10163(float);
+void PR10163 (void) {
+ float x[2];
+ test_PR10163(x[1]); // expected-warning{{uninitialized value}}
+}
+
diff --git a/test/Analysis/uninit-vals.m b/test/Analysis/uninit-vals.m
index 2cd5e0c11848..4b7e6f42cf8f 100644
--- a/test/Analysis/uninit-vals.m
+++ b/test/Analysis/uninit-vals.m
@@ -23,3 +23,12 @@ NSUInteger f8(A* x){
return n;
}
+
+
+// PR10163 -- don't warn for default-initialized float arrays.
+// (An additional test is in uninit-vals-ps-region.m)
+void test_PR10163(float);
+void PR10163 (void) {
+ float x[2] = {0};
+ test_PR10163(x[1]); // no-warning
+}
diff --git a/test/Analysis/variadic-method-types.m b/test/Analysis/variadic-method-types.m
index 018956ab1b2d..03c309a5004a 100644
--- a/test/Analysis/variadic-method-types.m
+++ b/test/Analysis/variadic-method-types.m
@@ -73,13 +73,13 @@ void f(id a, id<P> b, C* c, C<P> *d, FooType fooType, BarType barType) {
[NSDictionary dictionaryWithObjectsAndKeys:@"Foo", "Bar", nil]; // expected-warning {{Argument to 'NSDictionary' method 'dictionaryWithObjectsAndKeys:' should be an Objective-C pointer type, not 'char *'}}
[NSSet setWithObjects:@"Foo", "Bar", nil]; // expected-warning {{Argument to 'NSSet' method 'setWithObjects:' should be an Objective-C pointer type, not 'char *'}}
- [[[NSArray alloc] initWithObjects:@"Foo", "Bar", nil] autorelease]; // expected-warning {{Argument to method 'initWithObjects:' should be an Objective-C pointer type, not 'char *'}}
- [[[NSDictionary alloc] initWithObjectsAndKeys:@"Foo", "Bar", nil] autorelease]; // expected-warning {{Argument to method 'initWithObjectsAndKeys:' should be an Objective-C pointer type, not 'char *'}}
+ [[[NSArray alloc] initWithObjects:@"Foo", "Bar", nil] autorelease]; // expected-warning {{Argument to 'NSArray' method 'initWithObjects:' should be an Objective-C pointer type, not 'char *'}}
+ [[[NSDictionary alloc] initWithObjectsAndKeys:@"Foo", "Bar", nil] autorelease]; // expected-warning {{Argument to 'NSDictionary' method 'initWithObjectsAndKeys:' should be an Objective-C pointer type, not 'char *'}}
[[[NSDictionary alloc] initWithObjectsAndKeys:@"Foo", (void*) 0, nil] autorelease]; // no-warning
[[[NSDictionary alloc] initWithObjectsAndKeys:@"Foo", kCGImageSourceShouldCache, nil] autorelease]; // no-warning
[[[NSDictionary alloc] initWithObjectsAndKeys:@"Foo", fooType, nil] autorelease]; // no-warning
- [[[NSDictionary alloc] initWithObjectsAndKeys:@"Foo", barType, nil] autorelease]; // expected-warning {{Argument to method 'initWithObjectsAndKeys:' should be an Objective-C pointer type, not 'BarType'}}
- [[[NSSet alloc] initWithObjects:@"Foo", "Bar", nil] autorelease]; // expected-warning {{Argument to method 'initWithObjects:' should be an Objective-C pointer type, not 'char *'}}
+ [[[NSDictionary alloc] initWithObjectsAndKeys:@"Foo", barType, nil] autorelease]; // expected-warning {{Argument to 'NSDictionary' method 'initWithObjectsAndKeys:' should be an Objective-C pointer type, not 'BarType'}}
+ [[[NSSet alloc] initWithObjects:@"Foo", "Bar", nil] autorelease]; // expected-warning {{Argument to 'NSSet' method 'initWithObjects:' should be an Objective-C pointer type, not 'char *'}}
}
// This previously crashed the variadic argument checker.
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index e35413aaf8cc..0f00e5075a52 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -99,10 +99,10 @@ if(PYTHONINTERP_FOUND)
COMMENT "Running Clang and LLVM regression tests")
add_dependencies(check-all clang-test.deps)
if ( LLVM_INCLUDE_TESTS )
- add_dependencies(check-all check.deps ClangUnitTests)
+ add_dependencies(clang-test.deps check.deps ClangUnitTests)
endif ( LLVM_INCLUDE_TESTS )
add_dependencies(clang-test.deps
- llvm-dis opt
+ llvm-dis llc opt
FileCheck count not
)
set_target_properties(check-all PROPERTIES FOLDER "Clang tests")
@@ -110,7 +110,7 @@ if(PYTHONINTERP_FOUND)
add_dependencies(clang-test clang-test.deps)
add_dependencies(clang-test.deps
- clang clang-headers c-index-test
+ clang clang-headers c-index-test arcmt-test c-arcmt-test
)
endif()
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp b/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp
index ccadf416c977..15d86b7740c4 100644
--- a/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp
+++ b/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp
@@ -19,8 +19,9 @@ namespace D {
}
namespace C {
- class C {};
- void func(C);
+ class C {}; // expected-note {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'B::B' to 'const C::C &' for 1st argument}}
+ void func(C); // expected-note {{'C::func' declared here}} \
+ // expected-note {{passing argument to parameter here}}
C operator+(C,C);
D::D operator+(D::D,D::D);
}
@@ -32,7 +33,13 @@ namespace D {
namespace Test {
void test() {
func(A::A());
- func(B::B()); // expected-error {{use of undeclared identifier 'func'}}
+ // FIXME: namespace-aware typo correction causes an extra, misleading
+ // message in this case; some form of backtracking, diagnostic message
+ // delaying, or argument checking before emitting diagnostics is needed to
+ // avoid accepting and printing out a typo correction that proves to be
+ // incorrect once argument-dependent lookup resolution has occurred.
+ func(B::B()); // expected-error {{use of undeclared identifier 'func'; did you mean 'C::func'?}} \
+ // expected-error {{no viable conversion from 'B::B' to 'C::C'}}
func(C::C());
A::A() + A::A();
B::B() + B::B();
diff --git a/test/CXX/class/p6-0x.cpp b/test/CXX/class/p6-0x.cpp
new file mode 100644
index 000000000000..fc83e065fa6f
--- /dev/null
+++ b/test/CXX/class/p6-0x.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+
+class Trivial { int n; void f(); };
+class NonTrivial1 { NonTrivial1(const NonTrivial1 &); };
+class NonTrivial2 { NonTrivial2(NonTrivial2 &&); };
+class NonTrivial3 { NonTrivial3 operator=(const NonTrivial3 &); };
+class NonTrivial4 { NonTrivial4 operator=(NonTrivial4 &&); };
+class NonTrivial5 { ~NonTrivial5(); };
+
+static_assert(__is_trivial(Trivial), "Trivial is not trivial");
+static_assert(!__is_trivial(NonTrivial1), "NonTrivial1 is trivial");
+static_assert(!__is_trivial(NonTrivial2), "NonTrivial2 is trivial");
+static_assert(!__is_trivial(NonTrivial3), "NonTrivial3 is trivial");
+static_assert(!__is_trivial(NonTrivial4), "NonTrivial4 is trivial");
+static_assert(!__is_trivial(NonTrivial5), "NonTrivial5 is trivial");
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p1.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p1.cpp
index 40917b8ae3dc..cbb439ef5fec 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p1.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p1.cpp
@@ -7,13 +7,13 @@ template<typename T> void f(T) {}
template<typename T> static void g(T) {}
-template<> static void f<int>(int); // expected-error{{explicit specialization cannot have a storage class}}
+template<> static void f<int>(int); // expected-error{{explicit specialization has extraneous, inconsistent storage class 'static'}}
template static void f<float>(float); // expected-error{{explicit instantiation cannot have a storage class}}
template<> void f<double>(double);
template void f<long>(long);
-template<> static void g<int>(int); // expected-error{{explicit specialization cannot have a storage class}}
+template<> static void g<int>(int); // expected-warning{{explicit specialization cannot have a storage class}}
template static void g<float>(float); // expected-error{{explicit instantiation cannot have a storage class}}
template<> void g<double>(double);
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp
index fabfb5329da1..54da854dab55 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp
@@ -46,7 +46,7 @@ void j() {
U<auto> v; // expected-error{{'auto' not allowed in template argument}}
int n;
- (void)dynamic_cast<auto&>(S()); // expected-error{{'auto' not allowed here}}
+ (void)dynamic_cast<auto&>(n); // expected-error{{'auto' not allowed here}}
(void)static_cast<auto*>(&n); // expected-error{{'auto' not allowed here}}
(void)reinterpret_cast<auto*>(&n); // expected-error{{'auto' not allowed here}}
(void)const_cast<auto>(n); // expected-error{{'auto' not allowed here}}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp
index 06aeaa690a1a..8b4b70398471 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp
@@ -54,8 +54,7 @@ void f() {
auto *fail1 = 0; // expected-error {{variable 'fail1' with type 'auto *' has incompatible initializer of type 'int'}}
int **p;
- // FIXME: due to PR9233, we get the wrong diagnostic here.
- const auto **fail2(p); // desired-error {{variable 'fail2' with type 'auto const **' has incompatible initializer of type 'int **'}} expected-error {{cannot initialize}}
+ const auto **fail2(p); // expected-error {{variable 'fail2' with type 'auto const **' has incompatible initializer of type 'int **'}}
}
struct S {
diff --git a/test/CXX/except/except.spec/canonical.cpp b/test/CXX/except/except.spec/canonical.cpp
new file mode 100644
index 000000000000..9bc26de14440
--- /dev/null
+++ b/test/CXX/except/except.spec/canonical.cpp
@@ -0,0 +1,53 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+
+// PR10087: Make sure that we don't conflate exception specifications
+// from different functions in the canonical type system.
+namespace std
+{
+
+template <class _Tp> _Tp&& declval() noexcept;
+
+template <class _Tp, class... _Args>
+struct __is_nothrow_constructible
+{
+ static const bool value = noexcept(_Tp(declval<_Args>()...));
+};
+
+template<class, class _Traits, class _Allocator>
+class basic_string
+{
+public:
+ typedef typename _Traits::char_type value_type;
+ typedef _Allocator allocator_type;
+
+ basic_string()
+ noexcept(__is_nothrow_constructible<allocator_type>::value);
+};
+
+template <class, class, class _Compare>
+struct __map_value_compare
+{
+public:
+ __map_value_compare()
+ noexcept(__is_nothrow_constructible<_Compare>::value);
+};
+
+struct less
+{
+};
+
+struct map
+{
+ typedef __map_value_compare<int, short, less> __vc;
+ __vc vc_;
+};
+
+
+template<class T, class _Traits, class _Allocator>
+basic_string<T, _Traits, _Allocator>::basic_string() noexcept(__is_nothrow_constructible<allocator_type>::value) {}
+
+template <class T, class Value, class _Compare>
+__map_value_compare<T, Value, _Compare>::__map_value_compare()
+ noexcept(__is_nothrow_constructible<_Compare>::value) {}
+
+} // std
diff --git a/test/CXX/except/except.spec/p14-ir.cpp b/test/CXX/except/except.spec/p14-ir.cpp
index c681727e8ccf..81fbf7d97005 100644
--- a/test/CXX/except/except.spec/p14-ir.cpp
+++ b/test/CXX/except/except.spec/p14-ir.cpp
@@ -26,12 +26,12 @@ struct X4 {
struct X5 : X0, X4 { };
void test(X2 x2, X3 x3, X5 x5) {
- // CHECK: define linkonce_odr void @_ZN2X2C1ERKS_(%struct.X0* %this, %struct.X0*) unnamed_addr
+ // CHECK: define linkonce_odr void @_ZN2X2C1ERKS_(%struct.X2* %this, %struct.X2*) unnamed_addr
// CHECK: call void @_ZN2X2C2ERKS_({{.*}}) nounwind
// CHECK-NEXT: ret void
// CHECK-NEXT: }
X2 x2a(x2);
- // CHECK: define linkonce_odr void @_ZN2X3C1ERKS_(%struct.X0* %this, %struct.X0*) unnamed_addr
+ // CHECK: define linkonce_odr void @_ZN2X3C1ERKS_(%struct.X3* %this, %struct.X3*) unnamed_addr
// CHECK: call void @_ZN2X3C2ERKS_({{.*}}) nounwind
// CHECK-NEXT: ret void
// CHECK-NEXT: }
@@ -55,24 +55,25 @@ struct X8 : X6 { };
struct X9 : X6, X7 { };
void test() {
- // CHECK: define linkonce_odr void @_ZN2X8C1Ev(%struct.X0* %this) unnamed_addr
+ // CHECK: define linkonce_odr void @_ZN2X8C1Ev(%struct.X8* %this) unnamed_addr
// CHECK: call void @_ZN2X8C2Ev({{.*}}) nounwind
// CHECK-NEXT: ret void
X8();
- // CHECK: define linkonce_odr void @_ZN2X9C1Ev(%struct.X0* %this) unnamed_addr
+ // CHECK: define linkonce_odr void @_ZN2X9C1Ev(%struct.X9* %this) unnamed_addr
// FIXME: check that this is the end of the line here:
// CHECK: call void @_ZN2X9C2Ev({{.*}})
// CHECK-NEXT: ret void
X9();
- // CHECK: define linkonce_odr void @_ZN2X9C2Ev(%struct.X0* %this) unnamed_addr
+ // CHECK: define linkonce_odr void @_ZN2X9C2Ev(%struct.X9* %this) unnamed_addr
// CHECK: call void @_ZN2X6C2Ev({{.*}}) nounwind
// FIXME: and here:
+ // CHECK-NEXT: bitcast
// CHECK-NEXT: call void @_ZN2X7C2Ev({{.*}})
// CHECK: ret void
- // CHECK: define linkonce_odr void @_ZN2X8C2Ev(%struct.X0* %this) unnamed_addr
+ // CHECK: define linkonce_odr void @_ZN2X8C2Ev(%struct.X8* %this) unnamed_addr
// CHECK: call void @_ZN2X6C2Ev({{.*}}) nounwind
// CHECK-NEXT: ret void
}
diff --git a/test/CXX/special/class.copy/p33-0x.cpp b/test/CXX/special/class.copy/p33-0x.cpp
index 1e6a025ef31b..b196865c8225 100644
--- a/test/CXX/special/class.copy/p33-0x.cpp
+++ b/test/CXX/special/class.copy/p33-0x.cpp
@@ -23,3 +23,35 @@ void throw_move_only(X x) {
throw x2;
}
+namespace PR10142 {
+ struct X {
+ X();
+ X(X&&);
+ X(const X&) = delete; // expected-note 2{{function has been explicitly marked deleted here}}
+ };
+
+ void f(int i) {
+ X x;
+ try {
+ X x2;
+ if (i)
+ throw x2; // okay
+ throw x; // expected-error{{call to deleted constructor of 'PR10142::X'}}
+ } catch (...) {
+ }
+ }
+
+ template<typename T>
+ void f2(int i) {
+ T x;
+ try {
+ T x2;
+ if (i)
+ throw x2; // okay
+ throw x; // expected-error{{call to deleted constructor of 'PR10142::X'}}
+ } catch (...) {
+ }
+ }
+
+ template void f2<X>(int); // expected-note{{in instantiation of function template specialization 'PR10142::f2<PR10142::X>' requested here}}
+}
diff --git a/test/CXX/stmt.stmt/stmt.dcl/p3-0x.cpp b/test/CXX/stmt.stmt/stmt.dcl/p3-0x.cpp
index b41504488e8e..40b4c23841c8 100644
--- a/test/CXX/stmt.stmt/stmt.dcl/p3-0x.cpp
+++ b/test/CXX/stmt.stmt/stmt.dcl/p3-0x.cpp
@@ -30,13 +30,13 @@ struct Y {
void f();
void test_Y() {
- goto end;
- Y y;
+ goto end; // expected-error{{goto into protected scope}}
+ Y y; // expected-note{{jump bypasses variable with a non-trivial destructor}}
end:
f();
- goto inner;
+ goto inner; // expected-error{{goto into protected scope}}
{
- Y y2;
+ Y y2; // expected-note{{jump bypasses variable with a non-trivial destructor}}
inner:
f();
}
diff --git a/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp b/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
index 7bfa6fe58266..0c92f62582cf 100644
--- a/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
+++ b/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
@@ -129,7 +129,7 @@ void g() {
void *begin(); // expected-note {{selected 'begin' function with iterator type 'void *'}}
void *end();
};
- for (auto u : NoIncr()) { // expected-error {{arithmetic on pointer to void type}}
+ for (auto u : NoIncr()) { // expected-error {{arithmetic on a pointer to void type}}
}
struct NoNotEq {
diff --git a/test/CXX/temp/p3.cpp b/test/CXX/temp/p3.cpp
new file mode 100644
index 000000000000..16ebb381fd12
--- /dev/null
+++ b/test/CXX/temp/p3.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -verify %s
+
+template<typename T> struct S {
+ static int a, b;
+};
+
+template<typename T> int S<T>::a, S<T>::b; // expected-error {{can only declare a single entity}}
+
+// FIXME: the last two diagnostics here are terrible.
+template<typename T> struct A { static A a; } A<T>::a; // expected-error {{expected ';' after struct}} \
+ expected-error {{use of undeclared identifier 'T'}} \
+ expected-error {{cannot name the global scope}} \
+ expected-error {{no member named 'a' in the global namespace}}
+
+template<typename T> struct B { } f(); // expected-error {{expected ';' after struct}} \
+ expected-error {{requires a type specifier}}
+
+template<typename T> struct C { } // expected-error {{expected ';' after struct}}
+
+A<int> c;
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp
index 3c22cf349c9f..295f080a75d9 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp
@@ -71,7 +71,21 @@ void test_f3(int ***ip, volatile int ***vip) {
A<int> a0 = f3(ip);
A<volatile int> a1 = f3(vip);
}
-
+
+// Also accept conversions for pointer types which require removing
+// [[noreturn]].
+namespace noreturn_stripping {
+ template <class R>
+ void f(R (*function)());
+
+ void g() __attribute__ ((__noreturn__));
+ void h();
+ void test() {
+ f(g);
+ f(h);
+ }
+}
+
// - If P is a class, and P has the form template-id, then A can be a
// derived class of the deduced A. Likewise, if P is a pointer to a class
// of the form template-id, A can be a pointer to a derived class pointed
@@ -123,3 +137,12 @@ namespace N {
N::F<T1>(d); // OK
}
}
+
+namespace PR9233 {
+ template<typename T> void f(const T **q); // expected-note{{candidate template ignored: substitution failure [with T = int]}}
+
+ void g(int **p) {
+ f(p); // expected-error{{no matching function for call to 'f'}}
+ }
+
+}
diff --git a/test/CXX/temp/temp.res/temp.local/p3.cpp b/test/CXX/temp/temp.res/temp.local/p3.cpp
index 88f8963e6b62..54da8856fe46 100644
--- a/test/CXX/temp/temp.res/temp.local/p3.cpp
+++ b/test/CXX/temp/temp.res/temp.local/p3.cpp
@@ -22,11 +22,11 @@ template <class T> struct Derived: Base<int>, Base<char> {
namespace PR6717 {
template <typename T>
class WebVector {
- }
+ } // expected-error {{expected ';' after class}}
- WebVector(const WebVector<T>& other) { }
+ WebVector(const WebVector<T>& other) { } // expected-error{{undeclared identifier 'T'}} \
+ expected-error{{requires a type specifier}}
template <typename C>
- WebVector<T>& operator=(const C& other) { } // expected-error{{unknown type name 'WebVector'}} \
- // expected-error{{unqualified-id}}
+ WebVector<T>& operator=(const C& other) { } // expected-error{{undeclared identifier 'T'}}
}
diff --git a/test/CXX/temp/temp.spec/temp.explicit/p7.cpp b/test/CXX/temp/temp.spec/temp.explicit/p7.cpp
index b62e0cb9b1cd..7398dca7ba1c 100644
--- a/test/CXX/temp/temp.spec/temp.explicit/p7.cpp
+++ b/test/CXX/temp/temp.spec/temp.explicit/p7.cpp
@@ -7,14 +7,14 @@ struct X0 {
};
T* f0(T* ptr) {
- return ptr + 1; // expected-error{{pointer to function}}
+ return ptr + 1; // expected-error{{pointer to the function}}
}
static T* static_member;
};
template<typename T>
-T* X0<T>::static_member = ((T*)0) + 1; // expected-error{{pointer to function}}
+T* X0<T>::static_member = ((T*)0) + 1; // expected-error{{pointer to the function}}
template class X0<int>; // okay
diff --git a/test/CodeGen/annotate.c b/test/CodeGen/annotate.c
index ffaeebbca515..9ed187d1d170 100644
--- a/test/CodeGen/annotate.c
+++ b/test/CodeGen/annotate.c
@@ -7,4 +7,4 @@ void a(char *a) {
// CHECK: private unnamed_addr global
// CHECK: private unnamed_addr global
-// CHECK: @llvm.global.annotations = appending global [2 x %0]
+// CHECK: @llvm.global.annotations = appending global [2 x { i8*, i8*, i8*, i32 }]
diff --git a/test/CodeGen/arm-arguments.c b/test/CodeGen/arm-arguments.c
index 73bc03dac7f5..081bc89dcda7 100644
--- a/test/CodeGen/arm-arguments.c
+++ b/test/CodeGen/arm-arguments.c
@@ -61,7 +61,7 @@ struct s10 { int f0; int : 0; int : 0; };
struct s10 f10(void) {}
// APCS-GNU: define void @f11(
-// APCS-GNU: struct.s10* sret
+// APCS-GNU: struct.s11* sret
// AAPCS: define arm_aapcscc i32 @f11()
struct s11 { int : 0; int f0; };
struct s11 f11(void) {}
@@ -80,7 +80,7 @@ struct s13 { float f0; };
struct s13 f13(void) {}
// APCS-GNU: define void @f14(
-// APCS-GNU: struct.s13* sret
+// APCS-GNU: union.u14* sret
// AAPCS: define arm_aapcscc i32 @f14()
union u14 { float f0; };
union u14 f14(void) {}
diff --git a/test/CodeGen/arm-asm-variable.c b/test/CodeGen/arm-asm-variable.c
new file mode 100644
index 000000000000..865d1971e8b9
--- /dev/null
+++ b/test/CodeGen/arm-asm-variable.c
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -triple armv7-apple-darwin9 -emit-llvm -w -o - %s | FileCheck %s
+
+typedef long long int64_t;
+typedef unsigned int uint32_t;
+
+int64_t foo(int64_t v, volatile int64_t *p)
+{
+ register uint32_t rl asm("r1");
+ register uint32_t rh asm("r2");
+
+ int64_t r;
+ uint32_t t;
+
+ __asm__ __volatile__( \
+ "ldrexd%[_rl], %[_rh], [%[_p]]" \
+ : [_rl] "=&r" (rl), [_rh] "=&r" (rh) \
+ : [_p] "p" (p) : "memory");
+
+ // CHECK: call { i32, i32 } asm sideeffect "ldrexd$0, $1, [$2]", "={r1},={r2},r,~{memory}"(i64*
+
+ return r;
+}
+
+// Make sure we translate register names properly.
+void bar (void) {
+ register unsigned int rn asm("r14");
+ register unsigned int d asm("r2");
+
+ // CHECK: call i32 asm sideeffect "sub $1, $1, #32", "={r2},{lr}"
+ asm volatile ("sub %1, %1, #32" : "=r"(d) : "r"(rn));
+}
diff --git a/test/CodeGen/asm-errors.c b/test/CodeGen/asm-errors.c
index cd4d1ffa528d..438c82ba74db 100644
--- a/test/CodeGen/asm-errors.c
+++ b/test/CodeGen/asm-errors.c
@@ -1,6 +1,8 @@
// REQUIRES: x86-registered-target
-// RUN: not %clang_cc1 -triple i386-apple-darwin10 -emit-obj %s -o /dev/null > %t 2>&1
-// RUN: FileCheck %s < %t
+
+// RUN: true
+// UN: not %clang_cc1 -triple i386-apple-darwin10 -emit-obj %s -o /dev/null > %t 2>&1
+// UN: FileCheck %s < %t
int test1(int X) {
// CHECK: error: invalid instruction mnemonic 'abc'
diff --git a/test/CodeGen/asm-inout.c b/test/CodeGen/asm-inout.c
index 29142f7c5592..ce524fe70fe9 100644
--- a/test/CodeGen/asm-inout.c
+++ b/test/CodeGen/asm-inout.c
@@ -21,7 +21,7 @@ void test2() {
// PR7338
void test3(int *vout, int vin)
{
- // CHECK: call void asm "opr $0,$1", "=*r|m|r,r|m|r,~{di},~{dirflag},~{fpsr},~{flags}"
+ // CHECK: call void asm "opr $0,$1", "=*r|m|r,r|m|r,~{edi},~{dirflag},~{fpsr},~{flags}"
asm(
"opr %[vout],%[vin]"
: [vout] "=r,=m,=r" (*vout)
@@ -37,4 +37,3 @@ int test4(volatile int *addr) {
return (int)oldval;
// CHECK: call i8 asm "frob $0", "=r,0{{.*}}"(i8 -1)
}
-
diff --git a/test/CodeGen/asm.c b/test/CodeGen/asm.c
index eb112858718c..7199f09e1a3c 100644
--- a/test/CodeGen/asm.c
+++ b/test/CodeGen/asm.c
@@ -49,10 +49,10 @@ unsigned t9(unsigned int a) {
// PR3908
void t10(int r) {
__asm__("PR3908 %[lf] %[xx] %[li] %[r]" : [r] "+r" (r) : [lf] "mx" (0), [li] "mr" (0), [xx] "x" ((double)(0)));
-
+
// CHECK: @t10(
// CHECK:PR3908 $1 $3 $2 $0
-}
+}
// PR3373
@@ -119,7 +119,7 @@ int t16() {
void t17() {
int i;
__asm__ ( "nop": "=m"(i));
-
+
// CHECK: @t17()
// CHECK: call void asm "nop", "=*m,
}
@@ -127,7 +127,7 @@ void t17() {
// <rdar://problem/6841383>
int t18(unsigned data) {
int a, b;
-
+
asm("xyz" :"=a"(a), "=d"(b) : "a"(data));
return a + b;
// CHECK: t18(i32
@@ -140,7 +140,7 @@ int t18(unsigned data) {
// PR6780
int t19(unsigned data) {
int a, b;
-
+
asm("x{abc|def|ghi}z" :"=r"(a): "r"(data));
return a + b;
// CHECK: t19(i32
@@ -153,7 +153,7 @@ double t20(double x) {
register long double result;
__asm __volatile ("frndint" : "=t" (result) : "0" (x));
return result;
-
+
// CHECK: @t20
// CHECK: fpext double {{.*}} to x86_fp80
// CHECK-NEXT: call x86_fp80 asm sideeffect "frndint"
@@ -190,3 +190,17 @@ unsigned char t23(unsigned char a, unsigned char b) {
"edx", "cc");
return res;
}
+
+
+// PR10299 - fpsr, fpcr
+void test(void)
+{
+ __asm__ __volatile__( \
+ "finit" \
+ : \
+ : \
+ :"st","st(1)","st(2)","st(3)", \
+ "st(4)","st(5)","st(6)","st(7)", \
+ "fpsr","fpcr" \
+ );
+}
diff --git a/test/CodeGen/attr-weak-import.c b/test/CodeGen/attr-weak-import.c
new file mode 100644
index 000000000000..0707f59a608b
--- /dev/null
+++ b/test/CodeGen/attr-weak-import.c
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -triple x86_64-darwin-apple -emit-llvm -o - %s | FileCheck %s
+// rdar://9538608
+
+extern int A __attribute__((weak_import));
+int A;
+
+extern int B __attribute__((weak_import));
+extern int B;
+
+int C;
+extern int C __attribute__((weak_import));
+
+extern int D __attribute__((weak_import));
+extern int D __attribute__((weak_import));
+int D;
+
+extern int E __attribute__((weak_import));
+int E;
+extern int E __attribute__((weak_import));
+
+// CHECK: @A = global i32
+// CHECK-NOT: @B =
+// CHECK: @C = common global i32
+// CHECK: @D = global i32
+// CHECK: @E = global i32
+
diff --git a/test/CodeGen/attributes.c b/test/CodeGen/attributes.c
index 770ce766dfba..4e73af60439d 100644
--- a/test/CodeGen/attributes.c
+++ b/test/CodeGen/attributes.c
@@ -4,7 +4,7 @@
// CHECK: @t5 = weak global i32 2
int t5 __attribute__((weak)) = 2;
-// CHECK: @t13 = global %0 zeroinitializer, section "SECT"
+// CHECK: @t13 = global %struct.s0 zeroinitializer, section "SECT"
struct s0 { int x; };
struct s0 t13 __attribute__((section("SECT"))) = { 0 };
diff --git a/test/CodeGen/bitfield-2.c b/test/CodeGen/bitfield-2.c
index 8de432faa8ae..69ed5b11fe35 100644
--- a/test/CodeGen/bitfield-2.c
+++ b/test/CodeGen/bitfield-2.c
@@ -11,7 +11,7 @@
// CHECK-RECORD: *** Dumping IRgen Record Layout
// CHECK-RECORD: Record: struct s0
// CHECK-RECORD: Layout: <CGRecordLayout
-// CHECK-RECORD: LLVMType:<{ [3 x i8] }>
+// CHECK-RECORD: LLVMType:%struct.s0 = type <{ [3 x i8] }>
// CHECK-RECORD: IsZeroInitializable:1
// CHECK-RECORD: BitFields:[
// CHECK-RECORD: <CGBitFieldInfo Size:24 IsSigned:1
@@ -56,7 +56,7 @@ unsigned long long test_0() {
// CHECK-RECORD: *** Dumping IRgen Record Layout
// CHECK-RECORD: Record: struct s1
// CHECK-RECORD: Layout: <CGRecordLayout
-// CHECK-RECORD: LLVMType:<{ [2 x i8], i8 }>
+// CHECK-RECORD: LLVMType:%struct.s1 = type <{ [2 x i8], i8 }>
// CHECK-RECORD: IsZeroInitializable:1
// CHECK-RECORD: BitFields:[
// CHECK-RECORD: <CGBitFieldInfo Size:10 IsSigned:1
@@ -113,7 +113,7 @@ unsigned long long test_1() {
// CHECK-RECORD: *** Dumping IRgen Record Layout
// CHECK-RECORD: Record: union u2
// CHECK-RECORD: Layout: <CGRecordLayout
-// CHECK-RECORD: LLVMType:<{ i8 }>
+// CHECK-RECORD: LLVMType:%union.u2 = type <{ i8 }>
// CHECK-RECORD: IsZeroInitializable:1
// CHECK-RECORD: BitFields:[
// CHECK-RECORD: <CGBitFieldInfo Size:3 IsSigned:0
@@ -288,7 +288,7 @@ _Bool test_6() {
// CHECK-RECORD: *** Dumping IRgen Record Layout
// CHECK-RECORD: Record: struct s7
// CHECK-RECORD: Layout: <CGRecordLayout
-// CHECK-RECORD: LLVMType:{ i32, i32, i32, i8, [3 x i8], [4 x i8], [12 x i8] }
+// CHECK-RECORD: LLVMType:%struct.s7 = type { i32, i32, i32, i8, [3 x i8], [4 x i8], [12 x i8] }
// CHECK-RECORD: IsZeroInitializable:1
// CHECK-RECORD: BitFields:[
// CHECK-RECORD: <CGBitFieldInfo Size:5 IsSigned:1
diff --git a/test/CodeGen/blocksignature.c b/test/CodeGen/blocksignature.c
index 7526f19468ed..63fe1248a86d 100644
--- a/test/CodeGen/blocksignature.c
+++ b/test/CodeGen/blocksignature.c
@@ -2,13 +2,13 @@
// RUN: %clang_cc1 -fblocks -triple i686-apple-darwin9 %s -emit-llvm -o - | FileCheck %s -check-prefix=X32
// X64: @.str = private unnamed_addr constant [6 x i8] c"v8@?0\00"
-// X64: @__block_literal_global = internal constant %1 { i8** @_NSConcreteGlobalBlock, i32 1342177280,
+// X64: @__block_literal_global = internal constant {{.*}} { i8** @_NSConcreteGlobalBlock, i32 1342177280,
// X64: @.str1 = private unnamed_addr constant [12 x i8] c"i16@?0c8f12\00"
// X64: store i32 1073741824, i32*
// X32: [[STR1:@.*]] = private unnamed_addr constant [6 x i8] c"v4@?0\00"
-// X32: @__block_descriptor_tmp = internal constant [[FULL_DESCRIPTOR_T:%.*]] { i32 0, i32 20, i8* getelementptr inbounds ([6 x i8]* [[STR1]], i32 0, i32 0), i8* null }
-// X32: @__block_literal_global = internal constant [[GLOBAL_LITERAL_T:%.*]] { i8** @_NSConcreteGlobalBlock, i32 1342177280, i32 0, i8* bitcast (void (i8*)* @__block_global_{{.*}} to i8*), [[DESCRIPTOR_T:%.*]]* bitcast ([[FULL_DESCRIPTOR_T]]* @__block_descriptor_tmp to {{%.*}}*) }
+// X32: @__block_descriptor_tmp = internal constant [[FULL_DESCRIPTOR_T:.*]] { i32 0, i32 20, i8* getelementptr inbounds ([6 x i8]* [[STR1]], i32 0, i32 0), i8* null }
+// X32: @__block_literal_global = internal constant [[GLOBAL_LITERAL_T:.*]] { i8** @_NSConcreteGlobalBlock, i32 1342177280, i32 0, i8* bitcast (void (i8*)* @__block_global_{{.*}} to i8*), [[DESCRIPTOR_T:%.*]]* bitcast ([[FULL_DESCRIPTOR_T]]* @__block_descriptor_tmp to {{%.*}}*) }
// X32: [[STR2:@.*]] = private unnamed_addr constant [11 x i8] c"i12@?0c4f8\00"
// X32: @__block_descriptor_tmp{{.*}} = internal constant [[FULL_DESCRIPTOR_T]] { i32 0, i32 24, i8* getelementptr inbounds ([11 x i8]* [[STR2]], i32 0, i32 0), i8* null }
// X32: store i32 1073741824, i32*
diff --git a/test/CodeGen/blockstret.c b/test/CodeGen/blockstret.c
index e49b52a18853..d5dae6f3a614 100644
--- a/test/CodeGen/blockstret.c
+++ b/test/CodeGen/blockstret.c
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin9 %s -emit-llvm -o - | FileCheck %s -check-prefix=X64
// RUN: %clang_cc1 -fblocks -triple i686-apple-darwin9 %s -emit-llvm -o - | FileCheck %s -check-prefix=X32
-// X64: internal constant {{%.*}} { i8** @_NSConcreteGlobalBlock, i32 1879048192
+// X64: internal constant {{.*}} { i8** @_NSConcreteGlobalBlock, i32 1879048192
// X64: store i32 1610612736, i32* %want
// X32: @_NSConcreteGlobalBlock, i32 1879048192, i32 0,
diff --git a/test/CodeGen/builtin-expect.c b/test/CodeGen/builtin-expect.c
index 88479d90a092..664c6b6a470e 100644
--- a/test/CodeGen/builtin-expect.c
+++ b/test/CodeGen/builtin-expect.c
@@ -19,3 +19,29 @@ int main() {
// CHECK: call void @isigprocmask()
// CHECK: [[C:%.*]] = call i64 (...)* @bar()
+
+
+// CHECK: @test1
+int test1(int x) {
+// CHECK: @llvm.expect
+ if (__builtin_expect (x, 1))
+ return 0;
+ return x;
+}
+
+// CHECK: @test2
+int test2(int x) {
+// CHECK: @llvm.expect
+ switch(__builtin_expect(x, 5)) {
+ default:
+ return 0;
+ case 0:
+ case 1:
+ case 2:
+ return 1;
+ case 5:
+ return 5;
+ };
+
+ return 0;
+}
diff --git a/test/CodeGen/byval-memcpy-elim.c b/test/CodeGen/byval-memcpy-elim.c
index 8aa08fb07b2c..76cdafb5e8c5 100644
--- a/test/CodeGen/byval-memcpy-elim.c
+++ b/test/CodeGen/byval-memcpy-elim.c
@@ -18,3 +18,36 @@ void test1a(struct Test1S, struct Test2S);
void test1(struct Test1S *A, struct Test2S *B) {
test1a(*A, *B);
}
+
+// The above gets tricker when the byval argument requires higher alignment
+// than the natural alignment of the type in question.
+// rdar://9483886
+
+// Make sure we do generate a memcpy when we cannot guarantee alignment.
+struct Test3S {
+ int a,b,c,d,e,f,g,h,i,j,k,l;
+};
+void test2a(struct Test3S q);
+// CHECK: define void @test2(
+// CHECK: alloca %struct.Test3S, align 8
+// CHECK: memcpy
+// CHECK: call void @test2a
+void test2(struct Test3S *q) {
+ test2a(*q);
+}
+
+// But make sure we don't generate a memcpy when we can guarantee alignment.
+void fooey(void);
+// CHECK: define void @test3(
+// CHECK: alloca %struct.Test3S, align 8
+// CHECK: call void @fooey
+// CHECK-NOT: memcpy
+// CHECK: call void @test2a
+// CHECK-NOT: memcpy
+// CHECK: call void @test2a
+void test3(struct Test3S a) {
+ struct Test3S b = a;
+ fooey();
+ test2a(a);
+ test2a(b);
+}
diff --git a/test/CodeGen/call-knr-indirect.c b/test/CodeGen/call-knr-indirect.c
deleted file mode 100644
index 2e923b303cd0..000000000000
--- a/test/CodeGen/call-knr-indirect.c
+++ /dev/null
@@ -1,11 +0,0 @@
-// RUN: %clang %s -O0 -emit-llvm -S -o - | grep 'call.*rb_define_global_function'
-// This should call rb_define_global_function, not rb_f_chop.
-
-void rb_define_global_function (const char*,void(*)(),int);
-static void rb_f_chop();
-void Init_String() {
- rb_define_global_function("chop", rb_f_chop, 0);
-}
-static void rb_f_chop() {
-}
-
diff --git a/test/CodeGen/call.c b/test/CodeGen/call.c
new file mode 100644
index 000000000000..ef327751b3ad
--- /dev/null
+++ b/test/CodeGen/call.c
@@ -0,0 +1,39 @@
+// RUN: %clang %s -O0 -emit-llvm -S -o - | FileCheck %s
+
+// This should call rb_define_global_function, not rb_f_chop.
+void rb_define_global_function (const char*,void(*)(),int);
+static void rb_f_chop();
+void Init_String() {
+ rb_define_global_function("chop", rb_f_chop, 0);
+}
+static void rb_f_chop() {
+}
+
+// CHECK: call{{.*}}rb_define_global_function
+
+// PR10335
+typedef void (* JSErrorCallback)(void);
+void js_GetErrorMessage(void);
+void JS_ReportErrorNumber(JSErrorCallback errorCallback, ...);
+void Interpret() {
+ JS_ReportErrorNumber(js_GetErrorMessage, 0);
+
+ // CHECK: call void ({{.*}}, ...)* @JS_ReportErrorNumber({{.*}}@js_GetErrorMessage
+}
+
+
+
+
+// PR10337
+struct sigaction { int (*_sa_handler)(int); };
+typedef int SigHandler ();
+typedef struct sigaction sighandler_cxt;
+SigHandler *rl_set_sighandler(ohandler)
+sighandler_cxt *ohandler; {
+ return 0;
+}
+
+void rl_set_signals() {
+ SigHandler *oh;
+ oh = rl_set_sighandler(0);
+}
diff --git a/test/CodeGen/complex-indirect.c b/test/CodeGen/complex-indirect.c
new file mode 100644
index 000000000000..45eb1954842f
--- /dev/null
+++ b/test/CodeGen/complex-indirect.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin10 | FileCheck %s
+
+// Make sure this doesn't crash, and that we don't generate a byval alloca
+// with insufficient alignment.
+
+void a(int,int,int,int,int,int,__complex__ char);
+void b(__complex__ char *y) { a(0,0,0,0,0,0,*y); }
+// CHECK: define void @b
+// CHECK: alloca { i8, i8 }*, align 8
+// CHECK: call void @a(i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, { i8, i8 }* byval align 8
diff --git a/test/CodeGen/complex.c b/test/CodeGen/complex.c
index 055383ebbbe2..1212660e878d 100644
--- a/test/CodeGen/complex.c
+++ b/test/CodeGen/complex.c
@@ -93,3 +93,7 @@ void t6() {
double t7(double _Complex c) {
return __builtin_fabs(__real__(c));
}
+
+void t8() {
+ __complex__ int *x = &(__complex__ int){1};
+}
diff --git a/test/CodeGen/compound-literal.c b/test/CodeGen/compound-literal.c
index 4b995dbfef2e..0164c2b73862 100644
--- a/test/CodeGen/compound-literal.c
+++ b/test/CodeGen/compound-literal.c
@@ -1,12 +1,33 @@
-// RUN: %clang_cc1 < %s -emit-llvm
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
int* a = &(int){1};
struct s {int a, b, c;} * b = &(struct s) {1, 2, 3};
// Not working; complex constants are broken
// _Complex double * x = &(_Complex double){1.0f};
-int xxx() {
+void xxx() {
int* a = &(int){1};
struct s {int a, b, c;} * b = &(struct s) {1, 2, 3};
_Complex double * x = &(_Complex double){1.0f};
}
+
+// CHECK: define void @f()
+void f() {
+ typedef struct S { int x,y; } S;
+ // CHECK: [[S:%[a-zA-Z0-9.]+]] = alloca [[STRUCT:%[a-zA-Z0-9.]+]],
+ struct S s;
+ // CHECK-NEXT: [[COMPOUNDLIT:%[a-zA-Z0-9.]+]] = alloca [[STRUCT]]
+ // CHECK-NEXT: [[CX:%[a-zA-Z0-9.]+]] = getelementptr inbounds [[STRUCT]]* [[COMPOUNDLIT]], i32 0, i32 0
+ // CHECK-NEXT: [[SY:%[a-zA-Z0-9.]+]] = getelementptr inbounds [[STRUCT]]* [[S]], i32 0, i32 1
+ // CHECK-NEXT: [[TMP:%[a-zA-Z0-9.]+]] = load i32* [[SY]]
+ // CHECK-NEXT: store i32 [[TMP]], i32* [[CX]]
+ // CHECK-NEXT: [[CY:%[a-zA-Z0-9.]+]] = getelementptr inbounds [[STRUCT]]* [[COMPOUNDLIT]], i32 0, i32 1
+ // CHECK-NEXT: [[SX:%[a-zA-Z0-9.]+]] = getelementptr inbounds [[STRUCT]]* [[S]], i32 0, i32 0
+ // CHECK-NEXT: [[TMP:%[a-zA-Z0-9.]+]] = load i32* [[SX]]
+ // CHECK-NEXT: store i32 [[TMP]], i32* [[CY]]
+ // CHECK-NEXT: [[SI8:%[a-zA-Z0-9.]+]] = bitcast [[STRUCT]]* [[S]] to i8*
+ // CHECK-NEXT: [[COMPOUNDLITI8:%[a-zA-Z0-9.]+]] = bitcast [[STRUCT]]* [[COMPOUNDLIT]] to i8*
+ // CHECK-NEXT: call void @llvm.memcpy{{.*}}(i8* [[SI8]], i8* [[COMPOUNDLITI8]]
+ s = (S){s.y,s.x};
+ // CHECK-NEXT: ret void
+}
diff --git a/test/CodeGen/const-init.c b/test/CodeGen/const-init.c
index c6778630a0a0..9bc3bbafdeff 100644
--- a/test/CodeGen/const-init.c
+++ b/test/CodeGen/const-init.c
@@ -26,21 +26,21 @@ union s2 {
int g0 = (int)(&(((union s2 *) 0)->f0.f0) - 0);
-// CHECK: @g1x = global {{%.}} { double 1.000000e+00{{[0]*}}, double 0.000000e+00{{[0]*}} }
+// CHECK: @g1x = global { double, double } { double 1.000000e+00{{[0]*}}, double 0.000000e+00{{[0]*}} }
_Complex double g1x = 1.0f;
-// CHECK: @g1y = global {{%.}} { double 0.000000e+00{{[0]*}}, double 1.000000e+00{{[0]*}} }
+// CHECK: @g1y = global { double, double } { double 0.000000e+00{{[0]*}}, double 1.000000e+00{{[0]*}} }
_Complex double g1y = 1.0fi;
-// CHECK: @g1 = global {{%.}} { i8 1, i8 10 }
+// CHECK: @g1 = global { i8, i8 } { i8 1, i8 10 }
_Complex char g1 = (char) 1 + (char) 10 * 1i;
-// CHECK: @g2 = global %2 { i32 1, i32 10 }
+// CHECK: @g2 = global { i32, i32 } { i32 1, i32 10 }
_Complex int g2 = 1 + 10i;
-// CHECK: @g3 = global {{%.}} { float 1.000000e+00{{[0]*}}, float 1.000000e+0{{[0]*}}1 }
+// CHECK: @g3 = global { float, float } { float 1.000000e+00{{[0]*}}, float 1.000000e+0{{[0]*}}1 }
_Complex float g3 = 1.0 + 10.0i;
-// CHECK: @g4 = global {{%.}} { double 1.000000e+00{{[0]*}}, double 1.000000e+0{{[0]*}}1 }
+// CHECK: @g4 = global { double, double } { double 1.000000e+00{{[0]*}}, double 1.000000e+0{{[0]*}}1 }
_Complex double g4 = 1.0 + 10.0i;
-// CHECK: @g5 = global %2 zeroinitializer
+// CHECK: @g5 = global { i32, i32 } zeroinitializer
_Complex int g5 = (2 + 3i) == (5 + 7i);
-// CHECK: @g6 = global {{%.}} { double -1.100000e+0{{[0]*}}1, double 2.900000e+0{{[0]*}}1 }
+// CHECK: @g6 = global { double, double } { double -1.100000e+0{{[0]*}}1, double 2.900000e+0{{[0]*}}1 }
_Complex double g6 = (2.0 + 3.0i) * (5.0 + 7.0i);
// CHECK: @g7 = global i32 1
int g7 = (2 + 3i) * (5 + 7i) == (-11 + 29i);
@@ -52,14 +52,14 @@ int g9 = (2 + 3i) * (5 + 7i) != (-11 + 29i);
int g10 = (2.0 + 3.0i) * (5.0 + 7.0i) != (-11.0 + 29.0i);
// PR5108
-// CHECK: @gv1 = global %4 <{ i32 0, i8 7 }>, align 1
+// CHECK: @gv1 = global %struct.anon <{ i32 0, i8 7 }>, align 1
struct {
unsigned long a;
unsigned long b:3;
} __attribute__((__packed__)) gv1 = { .a = 0x0, .b = 7, };
// PR5118
-// CHECK: @gv2 = global %5 <{ i8 1, i8* null }>, align 1
+// CHECK: @gv2 = global %struct.anon.0 <{ i8 1, i8* null }>, align 1
struct {
unsigned char a;
char *b;
diff --git a/test/CodeGen/darwin-thread-specifier.c b/test/CodeGen/darwin-thread-specifier.c
new file mode 100644
index 000000000000..605d461aca72
--- /dev/null
+++ b/test/CodeGen/darwin-thread-specifier.c
@@ -0,0 +1,3 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.7.0 -emit-llvm -o - %s | FileCheck %s
+// CHECK: @b = thread_local global i32 5, align 4
+__thread int b = 5;
diff --git a/test/CodeGen/debug-info-iv.c b/test/CodeGen/debug-info-iv.c
new file mode 100644
index 000000000000..92654738cfc5
--- /dev/null
+++ b/test/CodeGen/debug-info-iv.c
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -triple x86_64-darwin-apple -Os -S -g -o - %s | FileCheck %s
+
+int calculate(int);
+static void test_indvars(int *Array1, int Array2[100][200]) {
+ unsigned i, j;
+ Array1[1] = Array2[3][6] = 12345;
+
+ for (i = 0; i < 100; i+=2)
+ Array1[i] = i; /* Step by non unit amount */
+
+ for (i = 3; i < 103; i++)
+ Array1[i] = i+4; /* Step with an offset */
+
+ for (i = 13; i < 100; i++)
+ for (j = 0; j < 100; j+=3) /* 2d array access */
+ Array2[i][j/3] = Array2[i][i];
+}
+
+
+int main() {
+ int Array[100][200], i, j;
+ double sum = 0.0;
+
+ for (i=0; i < 100; i+=2)
+ for (j=0; j < 200; j++)
+ Array[i][j] = 0;
+ test_indvars(Array[0], Array);
+
+//CHECK: .loc 2 30 3
+ for (i=0; i < 100; i+=2)
+ for (j=0; j < 200; j++)
+ sum += Array[i][j];
+
+ return calculate(sum);
+}
diff --git a/test/CodeGen/debug-info-member.c b/test/CodeGen/debug-info-member.c
new file mode 100644
index 000000000000..54066fa53060
--- /dev/null
+++ b/test/CodeGen/debug-info-member.c
@@ -0,0 +1,3 @@
+// RUN: %clang_cc1 -emit-llvm -g < %s | grep DW_TAG_member | grep \!3
+
+struct A { int x; } a;
diff --git a/test/CodeGen/debug-info.c b/test/CodeGen/debug-info.c
index 876c6c22423d..af2ce969bceb 100644
--- a/test/CodeGen/debug-info.c
+++ b/test/CodeGen/debug-info.c
@@ -54,3 +54,8 @@ __uint128_t foo128 ()
__uint128_t int128 = 44;
return int128;
}
+
+// CHECK: uint64x2_t
+typedef unsigned long long uint64_t;
+typedef uint64_t uint64x2_t __attribute__((ext_vector_type(2)));
+uint64x2_t extvectbar[4];
diff --git a/test/CodeGen/decl.c b/test/CodeGen/decl.c
index 29520d77ff48..21b75797f0c3 100644
--- a/test/CodeGen/decl.c
+++ b/test/CodeGen/decl.c
@@ -2,8 +2,8 @@
// CHECK: @test1.x = internal constant [12 x i32] [i32 1
// CHECK: @test2.x = internal unnamed_addr constant [13 x i32] [i32 1,
-// CHECK: @test5w = global %0 { i32 2, [4 x i8] undef }
-// CHECK: @test5y = global %union.test5u { double 7.300000e+0{{[0]*}}1 }
+// CHECK: @test5w = global { i32, [4 x i8] } { i32 2, [4 x i8] undef }
+// CHECK: @test5y = global { double } { double 7.300000e+0{{[0]*}}1 }
// CHECK: @test6.x = internal unnamed_addr constant %struct.SelectDest { i8 1, i8 2, i32 3, i32 0 }
diff --git a/test/CodeGen/designated-initializers.c b/test/CodeGen/designated-initializers.c
index d928296ef230..6561ce56d823 100644
--- a/test/CodeGen/designated-initializers.c
+++ b/test/CodeGen/designated-initializers.c
@@ -8,10 +8,10 @@ struct foo {
// CHECK: @u = global %union.anon zeroinitializer
union { int i; float f; } u = { };
-// CHECK: @u2 = global %1 { i32 0, [4 x i8] undef }
+// CHECK: @u2 = global { i32, [4 x i8] } { i32 0, [4 x i8] undef }
union { int i; double f; } u2 = { };
-// CHECK: @u3 = global %2 zeroinitializer
+// CHECK: @u3 = global %union.anon.1 zeroinitializer
union { double f; int i; } u3 = { };
// CHECK: @b = global [2 x i32] [i32 0, i32 22]
@@ -39,11 +39,11 @@ struct ds ds0 = { { { .a = 0 } } };
struct ds ds1 = { { .a = 1 } };
struct ds ds2 = { { .b = 1 } };
struct ds ds3 = { .a = 0 };
-// CHECK: @ds4 = global %3 { %4 { %struct.anon zeroinitializer, i16 0, %struct.anon { i16 1 } } }
+// CHECK: @ds4 = global %struct.ds { %struct.anon.3 { %struct.anon zeroinitializer, i16 0, %struct.anon.2 { i16 1 } } }
struct ds ds4 = { .c = 1 };
struct ds ds5 = { { { .a = 0 } }, .b = 1 };
struct ds ds6 = { { .a = 0, .b = 1 } };
-// CHECK: @ds7 = global %3 { %4 { %struct.anon { i16 2 }, i16 3, %struct.anon zeroinitializer } }
+// CHECK: @ds7 = global %struct.ds { %struct.anon.3 { %struct.anon { i16 2 }, i16 3, %struct.anon.2 zeroinitializer } }
struct ds ds7 = {
{ {
.a = 1
@@ -59,7 +59,7 @@ void test1(int argc, char **argv)
.b = 1024,
};
- // CHECK: bitcast %union.anon* %u2
+ // CHECK: bitcast %union.anon.4* %u2
// CHECK: call void @llvm.memset
union { int i; float f; } u2 = { };
diff --git a/test/CodeGen/flexible-array-init.c b/test/CodeGen/flexible-array-init.c
index 36323502a415..d3079dce3ddc 100644
--- a/test/CodeGen/flexible-array-init.c
+++ b/test/CodeGen/flexible-array-init.c
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -o - %s | FileCheck %s
struct { int x; int y[]; } a = { 1, 7, 11 };
-// CHECK: @a = global %0 { i32 1, [2 x i32] [i32 7, i32 11] }
+// CHECK: @a = global { i32, [2 x i32] } { i32 1, [2 x i32] [i32 7, i32 11] }
struct { int x; int y[]; } b = { 1, { 13, 15 } };
-// CHECK: @b = global %0 { i32 1, [2 x i32] [i32 13, i32 15] }
+// CHECK: @b = global { i32, [2 x i32] } { i32 1, [2 x i32] [i32 13, i32 15] }
diff --git a/test/CodeGen/functions.c b/test/CodeGen/functions.c
index a2c692d0ce3e..e51f93e57411 100644
--- a/test/CodeGen/functions.c
+++ b/test/CodeGen/functions.c
@@ -59,3 +59,9 @@ void f8_test() {
// CHECK: declare void @f8_user({{.*}}*)
// CHECK: declare void @f8_callback()
}
+
+// PR10204: don't crash
+static void test9_helper(void) {}
+void test9() {
+ (void) test9_helper;
+}
diff --git a/test/CodeGen/global-init.c b/test/CodeGen/global-init.c
index 351ca9e35ac7..074c2a065a86 100644
--- a/test/CodeGen/global-init.c
+++ b/test/CodeGen/global-init.c
@@ -27,12 +27,12 @@ struct ManyFields {
int f;
};
-// CHECK: global %0 { i32 1, i32 2, i32 0, i8 0, i32 0, i32 0 }
+// CHECK: global %struct.ManyFields { i32 1, i32 2, i32 0, i8 0, i32 0, i32 0 }
struct ManyFields FewInits = {1, 2};
// PR6766
-// CHECK: @l = global %1 { [24 x i8] c"f\00\00\00o\00\00\00o\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00", i32 1 }
+// CHECK: @l = global { [24 x i8], i32 } { [24 x i8] c"f\00\00\00o\00\00\00o\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00", i32 1 }
typedef __WCHAR_TYPE__ wchar_t;
struct K {
wchar_t L[6];
diff --git a/test/CodeGen/init.c b/test/CodeGen/init.c
index 0f94729a949e..599b4f23dbdc 100644
--- a/test/CodeGen/init.c
+++ b/test/CodeGen/init.c
@@ -115,3 +115,11 @@ void test11(struct test11S *P) {
// CHECK: store i32 4
// CHECK: ret void
}
+
+
+// Verify that we can convert a recursive struct with a memory that returns
+// an instance of the struct we're converting.
+struct test12 {
+ struct test12 (*p)(void);
+} test12g;
+
diff --git a/test/CodeGen/libcalls.c b/test/CodeGen/libcalls.c
index 828d7de6cb08..5ff684fd5b66 100644
--- a/test/CodeGen/libcalls.c
+++ b/test/CodeGen/libcalls.c
@@ -50,3 +50,26 @@ void test_pow(float a0, double a1, long double a2) {
// CHECK-NO: declare float @llvm.pow.f32(float, float) nounwind readonly
// CHECK-NO: declare double @llvm.pow.f64(double, double) nounwind readonly
// CHECK-NO: declare x86_fp80 @llvm.pow.f80(x86_fp80, x86_fp80) nounwind readonly
+
+// CHECK-YES: define void @test_fma
+// CHECK-NO: define void @test_fma
+void test_fma(float a0, double a1, long double a2) {
+ // CHECK-YES: call float @llvm.fma.f32
+ // CHECK-NO: call float @llvm.fma.f32
+ float l0 = fmaf(a0, a0, a0);
+
+ // CHECK-YES: call double @llvm.fma.f64
+ // CHECK-NO: call double @llvm.fma.f64
+ double l1 = fma(a1, a1, a1);
+
+ // CHECK-YES: call x86_fp80 @llvm.fma.f80
+ // CHECK-NO: call x86_fp80 @llvm.fma.f80
+ long double l2 = fmal(a2, a2, a2);
+}
+
+// CHECK-YES: declare float @llvm.fma.f32(float, float, float) nounwind readnone
+// CHECK-YES: declare double @llvm.fma.f64(double, double, double) nounwind readnone
+// CHECK-YES: declare x86_fp80 @llvm.fma.f80(x86_fp80, x86_fp80, x86_fp80) nounwind readnone
+// CHECK-NO: declare float @llvm.fma.f32(float, float, float) nounwind readnone
+// CHECK-NO: declare double @llvm.fma.f64(double, double, double) nounwind readnone
+// CHECK-NO: declare x86_fp80 @llvm.fma.f80(x86_fp80, x86_fp80, x86_fp80) nounwind readnone
diff --git a/test/CodeGen/mmx-inline-asm.c b/test/CodeGen/mmx-inline-asm.c
index c473a930ecc8..5d1371ed90a1 100644
--- a/test/CodeGen/mmx-inline-asm.c
+++ b/test/CodeGen/mmx-inline-asm.c
@@ -2,7 +2,7 @@
// <rdar://problem/9091220>
#include <mmintrin.h>
-// CHECK: type { x86_mmx, x86_mmx, x86_mmx, x86_mmx, x86_mmx, x86_mmx, x86_mmx }
+// CHECK: { x86_mmx, x86_mmx, x86_mmx, x86_mmx, x86_mmx, x86_mmx, x86_mmx }
void foo(long long fill) {
__m64 vfill = _mm_cvtsi64_m64(fill);
diff --git a/test/CodeGen/ms-anonymous-struct.c b/test/CodeGen/ms-anonymous-struct.c
index 3afe440cafe7..b41caab0309e 100644
--- a/test/CodeGen/ms-anonymous-struct.c
+++ b/test/CodeGen/ms-anonymous-struct.c
@@ -1,19 +1,19 @@
// RUN: %clang_cc1 -fms-extensions -emit-llvm -o - %s | FileCheck %s
+// CHECK: %struct.test = type { i32, %struct.nested2, i32 }
+// CHECK: %struct.nested2 = type { i32, %struct.nested1, i32 }
// CHECK: %struct.nested1 = type { i32, i32 }
typedef struct nested1 {
int a1;
int b1;
} NESTED1;
-// CHECK: %struct.nested2 = type { i32, %struct.nested1, i32 }
struct nested2 {
int a;
NESTED1;
int b;
};
-// CHECK: %struct.test = type { i32, %struct.nested2, i32 }
struct test {
int x;
struct nested2;
diff --git a/test/CodeGen/packed-union.c b/test/CodeGen/packed-union.c
index 0aeed008b752..31ce61440781 100644
--- a/test/CodeGen/packed-union.c
+++ b/test/CodeGen/packed-union.c
@@ -1,6 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm %s -o %t
-// RUN: grep "struct._attrs = type <{ i32, i8 }>" %t
typedef struct _attrs {
unsigned file_attributes;
unsigned char filename_length;
diff --git a/test/CodeGen/pragma-pack-3.c b/test/CodeGen/pragma-pack-3.c
index 676f0d77eba3..04b636e9c774 100644
--- a/test/CodeGen/pragma-pack-3.c
+++ b/test/CodeGen/pragma-pack-3.c
@@ -1,9 +1,7 @@
// RUN: %clang_cc1 -triple i386-apple-darwin9 %s -emit-llvm -o - | FileCheck -check-prefix X32 %s
-// CHECK-X32: %struct.menu = type <{ i8*, i8, i8 }>
// CHECK-X32: %union.command = type <{ i8*, [2 x i8] }>
// RUN: %clang_cc1 -triple x86_64-apple-darwin9 %s -emit-llvm -o - | FileCheck -check-prefix X64 %s
-// CHECK-X64: %struct.menu = type <{ i8*, i8, i8 }>
// CHECK-X64: %union.command = type <{ i8*, [2 x i8] }>
// <rdar://problem/7184250>
diff --git a/test/CodeGen/private-extern-redef.c b/test/CodeGen/private-extern-redef.c
new file mode 100644
index 000000000000..580ce9bd4a08
--- /dev/null
+++ b/test/CodeGen/private-extern-redef.c
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -triple x86_64-darwin-apple -emit-llvm -o - %s | FileCheck %s
+// rdar://9609649
+
+__private_extern__ const int I;
+__private_extern__ const int J = 927;
+
+__private_extern__ const int K;
+const int K = 37;
+
+const int L = 10;
+__private_extern__ const int L;
+
+__private_extern__ int M;
+int M = 20;
+
+__private_extern__ int N;
+int N;
+
+__private_extern__ int O;
+int O=1;
+
+__private_extern__ int P;
+extern int P;
+
+void bar(int);
+
+void foo() {
+ bar(I);
+}
+
+// CHECK: @J = hidden constant
+// CHECK: @K = hidden constant
+// CHECK: @L = constant
+// CHECK: @M = hidden global
+// CHECK: @O = hidden global
+// CHECK: @I = external hidden
+// CHECK: @N = common hidden global
+// CHECK-NOT: @P
+
diff --git a/test/CodeGen/struct-init.c b/test/CodeGen/struct-init.c
index 861c41e59cc3..8a605c1b67c8 100644
--- a/test/CodeGen/struct-init.c
+++ b/test/CodeGen/struct-init.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -emit-llvm-only
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
typedef struct _zend_ini_entry zend_ini_entry;
struct _zend_ini_entry {
@@ -29,3 +29,11 @@ typedef struct __simd64_uint32_t {
void foo() {
const uint32x2_t signBit = { (uint2) 0x80000000 };
}
+
+// CHECK: %struct.fp_struct_foo = type { void (i32)* }
+struct fp_struct_bar { int a; };
+
+struct fp_struct_foo {
+ void (*FP)(struct fp_struct_bar);
+} G;
+
diff --git a/test/CodeGen/struct.c b/test/CodeGen/struct.c
index 25477a052e8a..e1739314d7fc 100644
--- a/test/CodeGen/struct.c
+++ b/test/CodeGen/struct.c
@@ -181,3 +181,16 @@ range f18() {
rangepair rp;
return (rp = f18_ext()).range1;
}
+
+
+
+// Complex forward reference of struct.
+struct f19S;
+extern struct f19T {
+ struct f19S (*p)(void);
+} t;
+struct f19S { int i; };
+void f19(void) {
+ t.p();
+}
+
diff --git a/test/CodeGen/trapv.c b/test/CodeGen/trapv.c
index 7f192c634c88..f52dad556485 100644
--- a/test/CodeGen/trapv.c
+++ b/test/CodeGen/trapv.c
@@ -1,7 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -ftrapv %s -emit-llvm -o - | FileCheck %s
-// CHECK: [[I32O:%.*]] = type { i32, i1 }
-
unsigned int ui, uj, uk;
int i, j, k;
@@ -16,9 +14,9 @@ void test0() {
// CHECK: [[T1:%.*]] = load i32* @j
// CHECK-NEXT: [[T2:%.*]] = load i32* @k
- // CHECK-NEXT: [[T3:%.*]] = call [[I32O]] @llvm.sadd.with.overflow.i32(i32 [[T1]], i32 [[T2]])
- // CHECK-NEXT: [[T4:%.*]] = extractvalue [[I32O]] [[T3]], 0
- // CHECK-NEXT: [[T5:%.*]] = extractvalue [[I32O]] [[T3]], 1
+ // CHECK-NEXT: [[T3:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[T1]], i32 [[T2]])
+ // CHECK-NEXT: [[T4:%.*]] = extractvalue { i32, i1 } [[T3]], 0
+ // CHECK-NEXT: [[T5:%.*]] = extractvalue { i32, i1 } [[T3]], 1
// CHECK-NEXT: br i1 [[T5]]
// CHECK: call void @llvm.trap()
i = j + k;
@@ -30,9 +28,9 @@ void test1() {
opaque(i++);
// CHECK: [[T1:%.*]] = load i32* @i
- // CHECK-NEXT: [[T2:%.*]] = call [[I32O]] @llvm.sadd.with.overflow.i32(i32 [[T1]], i32 1)
- // CHECK-NEXT: [[T3:%.*]] = extractvalue [[I32O]] [[T2]], 0
- // CHECK-NEXT: [[T4:%.*]] = extractvalue [[I32O]] [[T2]], 1
+ // CHECK-NEXT: [[T2:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[T1]], i32 1)
+ // CHECK-NEXT: [[T3:%.*]] = extractvalue { i32, i1 } [[T2]], 0
+ // CHECK-NEXT: [[T4:%.*]] = extractvalue { i32, i1 } [[T2]], 1
// CHECK-NEXT: br i1 [[T4]]
// CHECK: call void @llvm.trap()
}
@@ -43,9 +41,9 @@ void test2() {
opaque(++i);
// CHECK: [[T1:%.*]] = load i32* @i
- // CHECK-NEXT: [[T2:%.*]] = call [[I32O]] @llvm.sadd.with.overflow.i32(i32 [[T1]], i32 1)
- // CHECK-NEXT: [[T3:%.*]] = extractvalue [[I32O]] [[T2]], 0
- // CHECK-NEXT: [[T4:%.*]] = extractvalue [[I32O]] [[T2]], 1
+ // CHECK-NEXT: [[T2:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[T1]], i32 1)
+ // CHECK-NEXT: [[T3:%.*]] = extractvalue { i32, i1 } [[T2]], 0
+ // CHECK-NEXT: [[T4:%.*]] = extractvalue { i32, i1 } [[T2]], 1
// CHECK-NEXT: br i1 [[T4]]
// CHECK: call void @llvm.trap()
}
diff --git a/test/CodeGen/union-init2.c b/test/CodeGen/union-init2.c
index 1386c27cc0bd..bf20696a22c1 100644
--- a/test/CodeGen/union-init2.c
+++ b/test/CodeGen/union-init2.c
@@ -1,11 +1,11 @@
// RUN: %clang_cc1 -emit-llvm %s -o - -triple i686-pc-linux-gnu | FileCheck %s
// Make sure we generate something sane instead of a ptrtoint
-// CHECK: bitcast (%0* @r to %union.x*), [4 x i8] undef
+// CHECK: bitcast ({ %union.x*, [4 x i8] }* @r to %union.x*), [4 x i8] undef
union x {long long b;union x* a;} r = {.a = &r};
-// CHECK: global %1 { [3 x i8] zeroinitializer, [5 x i8] undef }
+// CHECK: global { [3 x i8], [5 x i8] } { [3 x i8] zeroinitializer, [5 x i8] undef }
union z {
char a[3];
long long b;
diff --git a/test/CodeGen/vla.c b/test/CodeGen/vla.c
index e5114a5b0db9..c9612bc16032 100644
--- a/test/CodeGen/vla.c
+++ b/test/CodeGen/vla.c
@@ -88,13 +88,60 @@ int test2(int n)
// http://llvm.org/PR8567
// CHECK: define double @test_PR8567
double test_PR8567(int n, double (*p)[n][5]) {
- // CHECK: store [[vla_type:.*]] %p,
- // CHECK: load i32*
- // CHECK-NEXT: mul i32 40
- // CHECK-NEXT: [[byte_idx:%.*]] = mul i32 1
- // CHECK-NEXT: [[tmp_1:%.*]] = load [[vla_type]]*
- // CHECK-NEXT: [[tmp_2:%.*]] = bitcast [[vla_type]] [[tmp_1]] to i8*
- // CHECK-NEXT: [[idx:%.*]] = getelementptr inbounds i8* [[tmp_2]], i32 [[byte_idx]]
- // CHECK-NEXT: bitcast i8* [[idx]] to [[vla_type]]
+ // CHECK: [[NV:%.*]] = alloca i32, align 4
+ // CHECK-NEXT: [[PV:%.*]] = alloca [5 x double]*, align 4
+ // CHECK-NEXT: store
+ // CHECK-NEXT: store
+ // CHECK-NEXT: [[N:%.*]] = load i32* [[NV]], align 4
+ // CHECK-NEXT: [[P:%.*]] = load [5 x double]** [[PV]], align 4
+ // CHECK-NEXT: [[T0:%.*]] = mul nsw i32 1, [[N]]
+ // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [5 x double]* [[P]], i32 [[T0]]
+ // CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds [5 x double]* [[T1]], i32 2
+ // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds [5 x double]* [[T2]], i32 0, i32 3
+ // CHECK-NEXT: [[T4:%.*]] = load double* [[T3]]
+ // CHECK-NEXT: ret double [[T4]]
return p[1][2][3];
}
+
+int test4(unsigned n, char (*p)[n][n+1][6]) {
+ // CHECK: define i32 @test4(
+ // CHECK: [[N:%.*]] = alloca i32, align 4
+ // CHECK-NEXT: [[P:%.*]] = alloca [6 x i8]*, align 4
+ // CHECK-NEXT: [[P2:%.*]] = alloca [6 x i8]*, align 4
+ // CHECK-NEXT: store i32
+ // CHECK-NEXT: store [6 x i8]*
+
+ // VLA captures.
+ // CHECK-NEXT: [[DIM0:%.*]] = load i32* [[N]], align 4
+ // CHECK-NEXT: [[T0:%.*]] = load i32* [[N]], align 4
+ // CHECK-NEXT: [[DIM1:%.*]] = add i32 [[T0]], 1
+
+ // __typeof. FIXME: does this really need to be loaded?
+ // CHECK-NEXT: load [6 x i8]** [[P]]
+
+ // CHECK-NEXT: [[T0:%.*]] = load [6 x i8]** [[P]], align 4
+ // CHECK-NEXT: [[T1:%.*]] = load i32* [[N]], align 4
+ // CHECK-NEXT: [[T2:%.*]] = udiv i32 [[T1]], 2
+ // CHECK-NEXT: [[T3:%.*]] = mul nuw i32 [[DIM0]], [[DIM1]]
+ // CHECK-NEXT: [[T4:%.*]] = mul nsw i32 [[T2]], [[T3]]
+ // CHECK-NEXT: [[T5:%.*]] = getelementptr inbounds [6 x i8]* [[T0]], i32 [[T4]]
+ // CHECK-NEXT: [[T6:%.*]] = load i32* [[N]], align 4
+ // CHECK-NEXT: [[T7:%.*]] = udiv i32 [[T6]], 4
+ // CHECK-NEXT: [[T8:%.*]] = sub i32 0, [[T7]]
+ // CHECK-NEXT: [[T9:%.*]] = mul nuw i32 [[DIM0]], [[DIM1]]
+ // CHECK-NEXT: [[T10:%.*]] = mul nsw i32 [[T8]], [[T9]]
+ // CHECK-NEXT: [[T11:%.*]] = getelementptr inbounds [6 x i8]* [[T5]], i32 [[T10]]
+ // CHECK-NEXT: store [6 x i8]* [[T11]], [6 x i8]** [[P2]], align 4
+ __typeof(p) p2 = (p + n/2) - n/4;
+
+ // CHECK-NEXT: [[T0:%.*]] = load [6 x i8]** [[P2]], align 4
+ // CHECK-NEXT: [[T1:%.*]] = load [6 x i8]** [[P]], align 4
+ // CHECK-NEXT: [[T2:%.*]] = ptrtoint [6 x i8]* [[T0]] to i32
+ // CHECK-NEXT: [[T3:%.*]] = ptrtoint [6 x i8]* [[T1]] to i32
+ // CHECK-NEXT: [[T4:%.*]] = sub i32 [[T2]], [[T3]]
+ // CHECK-NEXT: [[T5:%.*]] = mul nuw i32 [[DIM0]], [[DIM1]]
+ // CHECK-NEXT: [[T6:%.*]] = mul nuw i32 6, [[T5]]
+ // CHECK-NEXT: [[T7:%.*]] = sdiv exact i32 [[T4]], [[T6]]
+ // CHECK-NEXT: ret i32 [[T7]]
+ return p2 - p;
+}
diff --git a/test/CodeGen/volatile-1.c b/test/CodeGen/volatile-1.c
index f54afffdadab..7c7a822e880c 100644
--- a/test/CodeGen/volatile-1.c
+++ b/test/CodeGen/volatile-1.c
@@ -4,7 +4,7 @@
volatile int i, j, k;
volatile int ar[5];
volatile char c;
-// CHECK: @ci = common global [[CINT:%.*]] zeroinitializer
+// CHECK: @ci = common global [[CINT:.*]] zeroinitializer
volatile _Complex int ci;
volatile struct S {
#ifdef __cplusplus
diff --git a/test/CodeGen/volatile-2.c b/test/CodeGen/volatile-2.c
index 1ceaf17dfcb4..490b7d776b9f 100644
--- a/test/CodeGen/volatile-2.c
+++ b/test/CodeGen/volatile-2.c
@@ -3,8 +3,8 @@
void test0() {
// CHECK: define void @test0()
// CHECK: [[F:%.*]] = alloca float
- // CHECK-NEXT: [[REAL:%.*]] = volatile load float* getelementptr inbounds ({{%.*}} @test0_v, i32 0, i32 0)
- // CHECK-NEXT: volatile load float* getelementptr inbounds ({{%.*}} @test0_v, i32 0, i32 1)
+ // CHECK-NEXT: [[REAL:%.*]] = volatile load float* getelementptr inbounds ({ float, float }* @test0_v, i32 0, i32 0)
+ // CHECK-NEXT: volatile load float* getelementptr inbounds ({{.*}} @test0_v, i32 0, i32 1)
// CHECK-NEXT: store float [[REAL]], float* [[F]], align 4
// CHECK-NEXT: ret void
extern volatile _Complex float test0_v;
@@ -13,10 +13,10 @@ void test0() {
void test1() {
// CHECK: define void @test1()
- // CHECK: [[REAL:%.*]] = volatile load float* getelementptr inbounds ({{%.*}} @test1_v, i32 0, i32 0)
- // CHECK-NEXT: [[IMAG:%.*]] = volatile load float* getelementptr inbounds ({{%.*}} @test1_v, i32 0, i32 1)
- // CHECK-NEXT: volatile store float [[REAL]], float* getelementptr inbounds ({{%.*}} @test1_v, i32 0, i32 0)
- // CHECK-NEXT: volatile store float [[IMAG]], float* getelementptr inbounds ({{%.*}} @test1_v, i32 0, i32 1)
+ // CHECK: [[REAL:%.*]] = volatile load float* getelementptr inbounds ({{.*}} @test1_v, i32 0, i32 0)
+ // CHECK-NEXT: [[IMAG:%.*]] = volatile load float* getelementptr inbounds ({{.*}} @test1_v, i32 0, i32 1)
+ // CHECK-NEXT: volatile store float [[REAL]], float* getelementptr inbounds ({{.*}} @test1_v, i32 0, i32 0)
+ // CHECK-NEXT: volatile store float [[IMAG]], float* getelementptr inbounds ({{.*}} @test1_v, i32 0, i32 1)
// CHECK-NEXT: ret void
extern volatile _Complex float test1_v;
test1_v = test1_v;
diff --git a/test/CodeGen/x86_32-arguments-darwin.c b/test/CodeGen/x86_32-arguments-darwin.c
index f7e2a5368de2..731d4f613f26 100644
--- a/test/CodeGen/x86_32-arguments-darwin.c
+++ b/test/CodeGen/x86_32-arguments-darwin.c
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -w -fblocks -triple i386-apple-darwin9 -emit-llvm -o %t %s
-// RUN: FileCheck < %t %s
+// RUN: %clang_cc1 -w -fblocks -triple i386-apple-darwin9 -target-cpu yonah -emit-llvm -o - %s | FileCheck %s
// CHECK: define signext i8 @f0()
char f0(void) {
@@ -232,7 +231,7 @@ v4i32 f55(v4i32 arg) { return arg+arg; }
// CHECK: i8 signext %a0, %struct.s56_0* byval align 4 %a1,
// CHECK: x86_mmx %a2.coerce, %struct.s56_1* byval align 4,
// CHECK: i64 %a4.coerce, %struct.s56_2* byval align 4,
-// CHECK: <4 x i32> %a6, %struct.s39* byval align 16 %a7,
+// CHECK: <4 x i32> %a6, %struct.s56_3* byval align 16 %a7,
// CHECK: <2 x double> %a8, %struct.s56_4* byval align 16 %a9,
// CHECK: <8 x i32> %a10, %struct.s56_5* byval align 4,
// CHECK: <4 x double> %a12, %struct.s56_6* byval align 4)
@@ -241,7 +240,7 @@ v4i32 f55(v4i32 arg) { return arg+arg; }
// CHECK: i32 %{{[^ ]*}}, %struct.s56_0* byval align 4 %{{[^ ]*}},
// CHECK: x86_mmx %{{[^ ]*}}, %struct.s56_1* byval align 4 %{{[^ ]*}},
// CHECK: i64 %{{[^ ]*}}, %struct.s56_2* byval align 4 %{{[^ ]*}},
-// CHECK: <4 x i32> %{{[^ ]*}}, %struct.s39* byval align 16 %{{[^ ]*}},
+// CHECK: <4 x i32> %{{[^ ]*}}, %struct.s56_3* byval align 16 %{{[^ ]*}},
// CHECK: <2 x double> %{{[^ ]*}}, %struct.s56_4* byval align 16 %{{[^ ]*}},
// CHECK: <8 x i32> {{[^ ]*}}, %struct.s56_5* byval align 4 %{{[^ ]*}},
// CHECK: <4 x double> {{[^ ]*}}, %struct.s56_6* byval align 4 %{{[^ ]*}})
diff --git a/test/CodeGen/x86_32-arguments-linux.c b/test/CodeGen/x86_32-arguments-linux.c
index 2f246f85b519..81dcaf6af571 100644
--- a/test/CodeGen/x86_32-arguments-linux.c
+++ b/test/CodeGen/x86_32-arguments-linux.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -w -fblocks -triple i386-pc-linux-gnu -emit-llvm -o %t %s
+// RUN: %clang_cc1 -w -fblocks -triple i386-pc-linux-gnu -target-cpu pentium4 -emit-llvm -o %t %s
// RUN: FileCheck < %t %s
// CHECK: define void @f56(
diff --git a/test/CodeGen/x86_32-arguments-nommx.c b/test/CodeGen/x86_32-arguments-nommx.c
new file mode 100644
index 000000000000..40362f796f6c
--- /dev/null
+++ b/test/CodeGen/x86_32-arguments-nommx.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -target-feature -mmx -target-feature +sse2 -triple i686-pc-linux-gnu -emit-llvm -o - %s | FileCheck %s
+
+// no-mmx should put mmx into memory
+typedef int __attribute__((vector_size (8))) i32v2;
+int a(i32v2 x) { return x[0]; }
+// CHECK: define i32 @a(i64 %x.coerce)
+
+// but SSE2 vectors should still go into an SSE2 register
+typedef int __attribute__((vector_size (16))) i32v4;
+int b(i32v4 x) { return x[0]; }
+// CHECK: define i32 @b(<4 x i32> %x)
diff --git a/test/CodeGen/x86_64-arguments.c b/test/CodeGen/x86_64-arguments.c
index 75c4788f7120..221c7d38a73d 100644
--- a/test/CodeGen/x86_64-arguments.c
+++ b/test/CodeGen/x86_64-arguments.c
@@ -42,8 +42,8 @@ void f7(e7 a0) {
// Test merging/passing of upper eightbyte with X87 class.
//
-// CHECK: define void @f8_1(%struct.s19* sret %agg.result)
-// CHECK: define void @f8_2(%struct.s19* byval align 16 %a0)
+// CHECK: define void @f8_1(%union.u8* sret %agg.result)
+// CHECK: define void @f8_2(%union.u8* byval align 16 %a0)
union u8 {
long double a;
int b;
@@ -58,7 +58,7 @@ struct s9 { int a; int b; int : 0; } f9(void) { while (1) {} }
struct s10 { int a; int b; int : 0; };
void f10(struct s10 a0) {}
-// CHECK: define void @f11(%struct.s19* sret %agg.result)
+// CHECK: define void @f11(%union.anon* sret %agg.result)
union { long double a; float b; } f11() { while (1) {} }
// CHECK: define i32 @f12_0()
@@ -147,7 +147,7 @@ struct f24s { long a; int b; };
struct f23S f24(struct f23S *X, struct f24s *P2) {
return *X;
- // CHECK: define %struct.f24s @f24(%struct.f23S* %X, %struct.f24s* %P2)
+ // CHECK: define { i64, i32 } @f24(%struct.f23S* %X, %struct.f24s* %P2)
}
// rdar://8248065
@@ -169,7 +169,7 @@ struct foo26 {
};
struct foo26 f26(struct foo26 *P) {
- // CHECK: define %struct.foo26 @f26(%struct.foo26* %P)
+ // CHECK: define { i32*, float* } @f26(%struct.foo26* %P)
return *P;
}
@@ -259,3 +259,48 @@ void f9122143()
func(ss);
}
+// CHECK: define double @f36(double %arg.coerce)
+typedef unsigned v2i32 __attribute((__vector_size__(8)));
+v2i32 f36(v2i32 arg) { return arg; }
+
+// CHECK: declare void @f38(<8 x float>)
+// CHECK: declare void @f37(<8 x float>)
+typedef float __m256 __attribute__ ((__vector_size__ (32)));
+typedef struct {
+ __m256 m;
+} s256;
+
+s256 x38;
+__m256 x37;
+
+void f38(s256 x);
+void f37(__m256 x);
+void f39() { f38(x38); f37(x37); }
+
+// The two next tests make sure that the struct below is passed
+// in the same way regardless of avx being used
+
+// CHECK: declare void @func40(%struct.t128* byval align 16)
+typedef float __m128 __attribute__ ((__vector_size__ (16)));
+typedef struct t128 {
+ __m128 m;
+ __m128 n;
+} two128;
+
+extern void func40(two128 s);
+void func41(two128 s) {
+ func40(s);
+}
+
+// CHECK: declare void @func42(%struct.t128_2* byval align 16)
+typedef struct xxx {
+ __m128 array[2];
+} Atwo128;
+typedef struct t128_2 {
+ Atwo128 x;
+} SA;
+
+extern void func42(SA s);
+void func43(SA s) {
+ func42(s);
+}
diff --git a/test/CodeGenCXX/anonymous-union-member-initializer.cpp b/test/CodeGenCXX/anonymous-union-member-initializer.cpp
index 2ddafecf6651..324ff4aee2b7 100644
--- a/test/CodeGenCXX/anonymous-union-member-initializer.cpp
+++ b/test/CodeGenCXX/anonymous-union-member-initializer.cpp
@@ -86,7 +86,7 @@ namespace test3 {
// CHECK-NEXT: [[UNION:%.*]] = getelementptr inbounds {{.*}} [[THIS]], i32 0, i32 0
// CHECK-NEXT: [[STRUCT:%.*]] = bitcast {{.*}}* [[UNION]] to
// CHECK-NEXT: [[CALLBACK:%.*]] = getelementptr inbounds {{.*}} [[STRUCT]], i32 0, i32 0
- // CHECK-NEXT: store void (i8*)* null, void (i8*)** [[CALLBACK]]
+ // CHECK: store
// CHECK-NEXT: [[UNION:%.*]] = getelementptr inbounds {{.*}} [[THIS]], i32 0, i32 0
// CHECK-NEXT: [[STRUCT:%.*]] = bitcast {{.*}}* [[UNION]] to
// CHECK-NEXT: [[CVALUE:%.*]] = getelementptr inbounds {{.*}} [[STRUCT]], i32 0, i32 1
@@ -114,3 +114,19 @@ template <typename T> struct Foo {
};
};
Foo<int> f;
+
+namespace PR9683 {
+ struct QueueEntry {
+ union {
+ struct {
+ void* mPtr;
+ union {
+ unsigned mSubmissionTag;
+ };
+ };
+ unsigned mValue;
+ };
+ QueueEntry() {}
+ };
+ QueueEntry QE;
+}
diff --git a/test/CodeGenCXX/attr-used.cpp b/test/CodeGenCXX/attr-used.cpp
index 26109e7c6300..2c82184081b9 100644
--- a/test/CodeGenCXX/attr-used.cpp
+++ b/test/CodeGenCXX/attr-used.cpp
@@ -2,8 +2,8 @@
// <rdar://problem/8684363>: clang++ not respecting __attribute__((used)) on destructors
struct X0 {
- // CHECK: define linkonce_odr void @_ZN2X0C1Ev
+ // CHECK: define linkonce_odr {{.*}} @_ZN2X0C1Ev
__attribute__((used)) X0() {}
- // CHECK: define linkonce_odr void @_ZN2X0D1Ev
+ // CHECK: define linkonce_odr {{.*}} @_ZN2X0D1Ev
__attribute__((used)) ~X0() {}
};
diff --git a/test/CodeGenCXX/block-byref-cxx-objc.cpp b/test/CodeGenCXX/block-byref-cxx-objc.cpp
index a4fbd6cb6233..135e0c755194 100644
--- a/test/CodeGenCXX/block-byref-cxx-objc.cpp
+++ b/test/CodeGenCXX/block-byref-cxx-objc.cpp
@@ -16,9 +16,9 @@ int main()
}
// CHECK: define internal void @__Block_byref_object_copy_
-// CHECK: call void @_ZN1AC1ERKS_
+// CHECK: call {{.*}} @_ZN1AC1ERKS_
// CHECK: define internal void @__Block_byref_object_dispose_
-// CHECK: call void @_ZN1AD1Ev
+// CHECK: call {{.*}} @_ZN1AD1Ev
// CHECK: define internal void @__copy_helper_block_
// CHECK: call void @_Block_object_assign
// CHECK: define internal void @__destroy_helper_block_
diff --git a/test/CodeGenCXX/blocks.cpp b/test/CodeGenCXX/blocks.cpp
index a4d5b86565e2..0e310bdbbc13 100644
--- a/test/CodeGenCXX/blocks.cpp
+++ b/test/CodeGenCXX/blocks.cpp
@@ -31,7 +31,7 @@ namespace test1 {
// ...unless they have mutable fields...
// CHECK: define void @_ZN5test15test3Ev()
- // CHECK: [[BLOCK:%.*]] = alloca [[BLOCK_T:%.*]],
+ // CHECK: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
// CHECK: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to void ()*
// CHECK: store void ()* [[T0]], void ()** @out
struct mut { mutable int x; };
@@ -43,7 +43,7 @@ namespace test1 {
// ...or non-trivial destructors...
// CHECK: define void @_ZN5test15test4Ev()
// CHECK: [[OBJ:%.*]] = alloca
- // CHECK: [[BLOCK:%.*]] = alloca [[BLOCK_T:%.*]],
+ // CHECK: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
// CHECK: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to void ()*
// CHECK: store void ()* [[T0]], void ()** @out
struct scope { int x; ~scope(); };
diff --git a/test/CodeGenCXX/class-layout.cpp b/test/CodeGenCXX/class-layout.cpp
index 96fbae8970e0..9569f476dd87 100644
--- a/test/CodeGenCXX/class-layout.cpp
+++ b/test/CodeGenCXX/class-layout.cpp
@@ -20,8 +20,8 @@ namespace Test3 {
namespace Test4 {
// Test from PR5589.
- // CHECK: %"struct.Test4::A" = type { i32, i8, float }
// CHECK: %"struct.Test4::B" = type { %"struct.Test4::A", i16, double }
+ // CHECK: %"struct.Test4::A" = type { i32, i8, float }
struct A {
int a;
char c;
diff --git a/test/CodeGenCXX/compound-literals.cpp b/test/CodeGenCXX/compound-literals.cpp
new file mode 100644
index 000000000000..cd44e97c6744
--- /dev/null
+++ b/test/CodeGenCXX/compound-literals.cpp
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+
+struct X {
+ X();
+ X(const X&);
+ X(const char*);
+ ~X();
+};
+
+struct Y {
+ int i;
+ X x;
+};
+
+// CHECK: define i32 @_Z1fv()
+int f() {
+ // CHECK: [[LVALUE:%[a-z0-9.]+]] = alloca
+ // CHECK-NEXT: [[I:%[a-z0-9]+]] = getelementptr inbounds {{.*}}* [[LVALUE]], i32 0, i32 0
+ // CHECK-NEXT: store i32 17, i32* [[I]]
+ // CHECK-NEXT: [[X:%[a-z0-9]+]] = getelementptr inbounds {{.*}} [[LVALUE]], i32 0, i32 1
+ // CHECK-NEXT: call void @_ZN1XC1EPKc({{.*}}[[X]]
+ // CHECK-NEXT: [[I:%[a-z0-9]+]] = getelementptr inbounds {{.*}} [[LVALUE]], i32 0, i32 0
+ // CHECK-NEXT: [[RESULT:%[a-z0-9]+]] = load i32*
+ // CHECK-NEXT: call void @_ZN1YD1Ev
+ // CHECK-NEXT: ret i32 [[RESULT]]
+ return ((Y){17, "seventeen"}).i;
+}
diff --git a/test/CodeGenCXX/const-init.cpp b/test/CodeGenCXX/const-init.cpp
index a8c6f304980b..797d1377f698 100644
--- a/test/CodeGenCXX/const-init.cpp
+++ b/test/CodeGenCXX/const-init.cpp
@@ -10,7 +10,7 @@ void f();
void (&fr)() = f;
struct S { int& a; };
-// CHECK: @s = global %0 { i32* @a }
+// CHECK: @s = global %struct.S { i32* @a }
S s = { a };
// PR5581
@@ -21,7 +21,7 @@ public:
unsigned f;
};
-// CHECK: @_ZN6PR55812g0E = global %1 { i32 1 }
+// CHECK: @_ZN6PR55812g0E = global %"class.PR5581::C" { i32 1 }
C g0 = { C::e1 };
}
diff --git a/test/CodeGenCXX/constructor-init.cpp b/test/CodeGenCXX/constructor-init.cpp
index 47e3b7b0bb90..a195afe0692f 100644
--- a/test/CodeGenCXX/constructor-init.cpp
+++ b/test/CodeGenCXX/constructor-init.cpp
@@ -113,6 +113,22 @@ namespace InitVTable {
B::B(int x) : A(x + 5) {}
}
+namespace rdar9694300 {
+ struct X {
+ int x;
+ };
+
+ // CHECK: define void @_ZN11rdar96943001fEv
+ void f() {
+ // CHECK: alloca
+ X x;
+ // CHECK-NEXT: [[I:%.*]] = alloca i32
+ // CHECK-NEXT: store i32 17, i32* [[I]]
+ int i = 17;
+ // CHECK-NEXT: ret void
+ }
+}
+
template<typename T>
struct X {
X(const X &);
diff --git a/test/CodeGenCXX/constructors.cpp b/test/CodeGenCXX/constructors.cpp
index 75588ce06ce0..ec7f06c868a9 100644
--- a/test/CodeGenCXX/constructors.cpp
+++ b/test/CodeGenCXX/constructors.cpp
@@ -83,12 +83,12 @@ struct D : A {
D::D(int x, ...) : A(ValueClass(x, x+1)), mem(x*x) {}
-// CHECK: define void @_ZN1DC1Eiz(%struct.B* %this, i32 %x, ...) unnamed_addr
+// CHECK: define void @_ZN1DC1Eiz(%struct.D* %this, i32 %x, ...) unnamed_addr
// CHECK: call void @_ZN10ValueClassC1Eii(
// CHECK: call void @_ZN1AC2E10ValueClass(
// CHECK: call void @_ZN6MemberC1Ei(
-// CHECK: define void @_ZN1DC2Eiz(%struct.B* %this, i32 %x, ...) unnamed_addr
+// CHECK: define void @_ZN1DC2Eiz(%struct.D* %this, i32 %x, ...) unnamed_addr
// CHECK: call void @_ZN10ValueClassC1Eii(
// CHECK: call void @_ZN1AC2E10ValueClass(
// CHECK: call void @_ZN6MemberC1Ei(
@@ -104,3 +104,14 @@ namespace test0 {
C tmp = in;
}
}
+
+namespace test1 {
+ struct A { A(); void *ptr; };
+ struct B { B(); int x; A a[0]; };
+ B::B() {}
+ // CHECK: define void @_ZN5test11BC2Ev(
+ // CHECK: [[THIS:%.*]] = load [[B:%.*]]**
+ // CHECK-NEXT: [[A:%.*]] = getelementptr inbounds [[B:%.*]]* [[THIS]], i32 0, i32 1
+ // CHECK-NEXT: [[BEGIN:%.*]] = getelementptr inbounds [0 x {{%.*}}]* [[A]], i32 0, i32 0
+ // CHECK-NEXT: ret void
+}
diff --git a/test/CodeGenCXX/copy-constructor-elim-2.cpp b/test/CodeGenCXX/copy-constructor-elim-2.cpp
index 4f4a8e998bee..a4a688f737d7 100644
--- a/test/CodeGenCXX/copy-constructor-elim-2.cpp
+++ b/test/CodeGenCXX/copy-constructor-elim-2.cpp
@@ -3,7 +3,7 @@
struct A { int x; A(int); ~A(); };
A f() { return A(0); }
// CHECK: define void @_Z1fv
-// CHECK: call void @_ZN1AC1Ei
+// CHECK: call {{.*}} @_ZN1AC1Ei
// CHECK-NEXT: ret void
// Verify that we do not elide copies when constructing a base class.
@@ -21,14 +21,14 @@ namespace no_elide_base {
Derived(const Other &O);
};
- // CHECK: define void @_ZN13no_elide_base7DerivedC1ERKNS_5OtherE(%"struct.no_elide_base::Derived"* %this, %"struct.PR8683::A"* %O) unnamed_addr
+ // CHECK: define {{.*}} @_ZN13no_elide_base7DerivedC1ERKNS_5OtherE(%"struct.no_elide_base::Derived"* %this, %"struct.no_elide_base::Other"* %O) unnamed_addr
Derived::Derived(const Other &O)
- // CHECK: call void @_ZNK13no_elide_base5OthercvNS_4BaseEEv
- // CHECK: call void @_ZN13no_elide_base4BaseC2ERKS0_
- // CHECK: call void @_ZN13no_elide_base4BaseD1Ev
+ // CHECK: call {{.*}} @_ZNK13no_elide_base5OthercvNS_4BaseEEv
+ // CHECK: call {{.*}} @_ZN13no_elide_base4BaseC2ERKS0_
+ // CHECK: call {{.*}} @_ZN13no_elide_base4BaseD1Ev
: Base(O)
{
- // CHECK: ret void
+ // CHECK: ret
}
}
@@ -48,7 +48,7 @@ struct B {
void f() {
// Verify that we don't mark the copy constructor in this expression as elidable.
- // CHECK: call void @_ZN6PR86831AC1ERKS0_
+ // CHECK: call {{.*}} @_ZN6PR86831AC1ERKS0_
A a = (B().a);
}
diff --git a/test/CodeGenCXX/copy-constructor-synthesis-2.cpp b/test/CodeGenCXX/copy-constructor-synthesis-2.cpp
index a5566797d48b..d028a28fdd67 100644
--- a/test/CodeGenCXX/copy-constructor-synthesis-2.cpp
+++ b/test/CodeGenCXX/copy-constructor-synthesis-2.cpp
@@ -3,5 +3,5 @@
struct A { virtual void a(); };
A x(A& y) { return y; }
-// CHECK: define linkonce_odr void @_ZN1AC1ERKS_(%struct.A* %this, %struct.A*) unnamed_addr
+// CHECK: define linkonce_odr {{.*}} @_ZN1AC1ERKS_(%struct.A* %this, %struct.A*) unnamed_addr
// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1A, i64 0, i64 2)
diff --git a/test/CodeGenCXX/copy-initialization.cpp b/test/CodeGenCXX/copy-initialization.cpp
index 62b9f2678a43..aecd64ec1aac 100644
--- a/test/CodeGenCXX/copy-initialization.cpp
+++ b/test/CodeGenCXX/copy-initialization.cpp
@@ -12,7 +12,7 @@ struct Bar {
void f(Foo);
-// CHECK: define void @_Z1g3Foo(%struct.Bar* %foo)
+// CHECK: define void @_Z1g3Foo(%struct.Foo* %foo)
void g(Foo foo) {
// CHECK: call void @_ZN3BarC1Ev
// CHECK: @_ZNK3BarcvRK3FooEv
diff --git a/test/CodeGenCXX/cxx0x-defaulted-templates.cpp b/test/CodeGenCXX/cxx0x-defaulted-templates.cpp
index 3d4000e4994c..09eb4fe7a7f6 100644
--- a/test/CodeGenCXX/cxx0x-defaulted-templates.cpp
+++ b/test/CodeGenCXX/cxx0x-defaulted-templates.cpp
@@ -5,15 +5,15 @@ struct X {
X();
};
-// CHECK: define void @_ZN1XIbEC1Ev
-// CHECK: define void @_ZN1XIbEC2Ev
+// CHECK: define {{.*}} @_ZN1XIbEC1Ev
+// CHECK: define {{.*}} @_ZN1XIbEC2Ev
template <> X<bool>::X() = default;
-// CHECK: define weak_odr void @_ZN1XIiEC1Ev
-// CHECK: define weak_odr void @_ZN1XIiEC2Ev
+// CHECK: define weak_odr {{.*}} @_ZN1XIiEC1Ev
+// CHECK: define weak_odr {{.*}} @_ZN1XIiEC2Ev
template <typename T> X<T>::X() = default;
template X<int>::X();
-// CHECK: define linkonce_odr void @_ZN1XIcEC1Ev
-// CHECK: define linkonce_odr void @_ZN1XIcEC2Ev
+// CHECK: define linkonce_odr {{.*}} @_ZN1XIcEC1Ev
+// CHECK: define linkonce_odr {{.*}} @_ZN1XIcEC2Ev
X<char> x;
diff --git a/test/CodeGenCXX/cxx0x-delegating-ctors.cpp b/test/CodeGenCXX/cxx0x-delegating-ctors.cpp
index 15c8e7f5d827..0bac492796f8 100644
--- a/test/CodeGenCXX/cxx0x-delegating-ctors.cpp
+++ b/test/CodeGenCXX/cxx0x-delegating-ctors.cpp
@@ -26,28 +26,28 @@ delegator::delegator() {
delegator::delegator(bool)
{}
-// CHECK: define void @_ZN9delegatorC1Ec
-// CHECK: void @_ZN9delegatorC1Eb
+// CHECK: define {{.*}} @_ZN9delegatorC1Ec
+// CHECK: {{.*}} @_ZN9delegatorC1Eb
// CHECK: void @__cxa_throw
// CHECK: void @_ZSt9terminatev
-// CHECK: void @_ZN9delegatorD1Ev
-// CHECK: define void @_ZN9delegatorC2Ec
-// CHECK: void @_ZN9delegatorC2Eb
+// CHECK: {{.*}} @_ZN9delegatorD1Ev
+// CHECK: define {{.*}} @_ZN9delegatorC2Ec
+// CHECK: {{.*}} @_ZN9delegatorC2Eb
// CHECK: void @__cxa_throw
// CHECK: void @_ZSt9terminatev
-// CHECK: void @_ZN9delegatorD2Ev
+// CHECK: {{.*}} @_ZN9delegatorD2Ev
delegator::delegator(char)
: delegator(true) {
throw 0;
}
-// CHECK: define void @_ZN9delegatorC1Ei
-// CHECK: void @_ZN9delegatorC1Ev
+// CHECK: define {{.*}} @_ZN9delegatorC1Ei
+// CHECK: {{.*}} @_ZN9delegatorC1Ev
// CHECK-NOT: void @_ZSt9terminatev
// CHECK: ret
// CHECK-NOT: void @_ZSt9terminatev
-// CHECK: define void @_ZN9delegatorC2Ei
-// CHECK: void @_ZN9delegatorC2Ev
+// CHECK: define {{.*}} @_ZN9delegatorC2Ei
+// CHECK: {{.*}} @_ZN9delegatorC2Ev
// CHECK-NOT: void @_ZSt9terminatev
// CHECK: ret
// CHECK-NOT: void @_ZSt9terminatev
diff --git a/test/CodeGenCXX/default-constructor-default-argument.cpp b/test/CodeGenCXX/default-constructor-default-argument.cpp
index f2c7f6d12a34..374a967e3e2a 100644
--- a/test/CodeGenCXX/default-constructor-default-argument.cpp
+++ b/test/CodeGenCXX/default-constructor-default-argument.cpp
@@ -5,4 +5,4 @@ struct A { A(int x = 2); };
struct B : public A {};
B x;
-// CHECK: call void @_ZN1AC2Ei
+// CHECK: call {{.*}} @_ZN1AC2Ei
diff --git a/test/CodeGenCXX/default-constructor-template-member.cpp b/test/CodeGenCXX/default-constructor-template-member.cpp
index 422cc099ad6c..0dd64dfcb4c9 100644
--- a/test/CodeGenCXX/default-constructor-template-member.cpp
+++ b/test/CodeGenCXX/default-constructor-template-member.cpp
@@ -5,6 +5,6 @@ struct B { A<int> x; };
void a() {
B b;
}
-// CHECK: call void @_ZN1BC1Ev
-// CHECK: define linkonce_odr void @_ZN1BC1Ev(%struct.B* %this) unnamed_addr
-// CHECK: call void @_ZN1AIiEC1Ev
+// CHECK: call {{.*}} @_ZN1BC1Ev
+// CHECK: define linkonce_odr {{.*}} @_ZN1BC1Ev(%struct.B* %this) unnamed_addr
+// CHECK: call {{.*}} @_ZN1AIiEC1Ev
diff --git a/test/CodeGenCXX/delete.cpp b/test/CodeGenCXX/delete.cpp
index ddc7bb8dac28..08ce0de3b5c3 100644
--- a/test/CodeGenCXX/delete.cpp
+++ b/test/CodeGenCXX/delete.cpp
@@ -54,7 +54,7 @@ namespace test0 {
delete a;
}
- // CHECK: define linkonce_odr void @_ZN5test01AD1Ev(%class.A* %this) unnamed_addr
+ // CHECK: define linkonce_odr void @_ZN5test01AD1Ev(%"struct.test0::A"* %this) unnamed_addr
// CHECK: define linkonce_odr void @_ZN5test01AdlEPv
}
@@ -67,31 +67,22 @@ namespace test1 {
// CHECK: define void @_ZN5test14testEPA10_A20_NS_1AE(
void test(A (*arr)[10][20]) {
delete [] arr;
- // CHECK: icmp eq [10 x [20 x [[S:%.*]]]]* [[PTR:%.*]], null
+ // CHECK: icmp eq [10 x [20 x [[A:%.*]]]]* [[PTR:%.*]], null
// CHECK-NEXT: br i1
- // CHECK: [[ARR:%.*]] = getelementptr inbounds [10 x [20 x [[S]]]]* [[PTR]], i32 0, i32 0, i32 0
- // CHECK-NEXT: bitcast {{.*}} to i8*
- // CHECK-NEXT: [[ALLOC:%.*]] = getelementptr inbounds {{.*}}, i64 -8
- // CHECK-NEXT: bitcast i8* [[ALLOC]] to i64*
- // CHECK-NEXT: load
- // CHECK-NEXT: store i64 {{.*}}, i64* [[IDX:%.*]]
-
- // CHECK: load i64* [[IDX]]
- // CHECK-NEXT: icmp ne {{.*}}, 0
- // CHECK-NEXT: br i1
-
- // CHECK: load i64* [[IDX]]
- // CHECK-NEXT: [[I:%.*]] = sub i64 {{.*}}, 1
- // CHECK-NEXT: getelementptr inbounds [[S]]* [[ARR]], i64 [[I]]
- // CHECK-NEXT: call void @_ZN5test11AD1Ev(
- // CHECK-NEXT: br label
-
- // CHECK: load i64* [[IDX]]
- // CHECK-NEXT: sub
- // CHECK-NEXT: store {{.*}}, i64* [[IDX]]
- // CHECK-NEXT: br label
-
+ // CHECK: [[BEGIN:%.*]] = getelementptr inbounds [10 x [20 x [[A]]]]* [[PTR]], i32 0, i32 0, i32 0
+ // CHECK-NEXT: [[T0:%.*]] = bitcast [[A]]* [[BEGIN]] to i8*
+ // CHECK-NEXT: [[ALLOC:%.*]] = getelementptr inbounds i8* [[T0]], i64 -8
+ // CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[ALLOC]] to i64*
+ // CHECK-NEXT: [[COUNT:%.*]] = load i64* [[T1]]
+ // CHECK: [[END:%.*]] = getelementptr inbounds [[A]]* [[BEGIN]], i64 [[COUNT]]
+ // CHECK-NEXT: [[ISEMPTY:%.*]] = icmp eq [[A]]* [[BEGIN]], [[END]]
+ // CHECK-NEXT: br i1 [[ISEMPTY]],
+ // CHECK: [[PAST:%.*]] = phi [[A]]* [ [[END]], {{%.*}} ], [ [[CUR:%.*]], {{%.*}} ]
+ // CHECK-NEXT: [[CUR:%.*]] = getelementptr inbounds [[A]]* [[PAST]], i64 -1
+ // CHECK-NEXT: call void @_ZN5test11AD1Ev([[A]]* [[CUR]])
+ // CHECK-NEXT: [[ISDONE:%.*]] = icmp eq [[A]]* [[CUR]], [[BEGIN]]
+ // CHECK-NEXT: br i1 [[ISDONE]]
// CHECK: call void @_ZdaPv(i8* [[ALLOC]])
}
}
@@ -112,3 +103,22 @@ namespace test3 {
delete a;
}
}
+
+namespace test4 {
+ // PR10341: ::delete with a virtual destructor
+ struct X {
+ virtual ~X();
+ void operator delete (void *);
+ };
+
+ // CHECK: define void @_ZN5test421global_delete_virtualEPNS_1XE
+ void global_delete_virtual(X *xp) {
+ // CHECK: [[VTABLE:%.*]] = load void ([[X:%.*]])***
+ // CHECK-NEXT: [[VFN:%.*]] = getelementptr inbounds void ([[X]])** [[VTABLE]], i64 0
+ // CHECK-NEXT: [[VFNPTR:%.*]] = load void ([[X]])** [[VFN]]
+ // CHECK-NEXT: call void [[VFNPTR]]([[X]] [[OBJ:%.*]])
+ // CHECK-NEXT: [[OBJVOID:%.*]] = bitcast [[X]] [[OBJ]] to i8*
+ // CHECK-NEXT: call void @_ZdlPv(i8* [[OBJVOID]]) nounwind
+ ::delete xp;
+ }
+}
diff --git a/test/CodeGenCXX/destructors.cpp b/test/CodeGenCXX/destructors.cpp
index 94d88334f85b..33819858149b 100644
--- a/test/CodeGenCXX/destructors.cpp
+++ b/test/CodeGenCXX/destructors.cpp
@@ -40,11 +40,11 @@ namespace PR7526 {
struct allocator_derived : allocator { };
- // CHECK: define void @_ZN6PR75269allocatorD2Ev(%"struct.PR5529::A"* %this) unnamed_addr
+ // CHECK: define void @_ZN6PR75269allocatorD2Ev(%"struct.PR7526::allocator"* %this) unnamed_addr
// CHECK: call void @__cxa_call_unexpected
allocator::~allocator() throw() { foo(); }
- // CHECK: define linkonce_odr void @_ZN6PR752617allocator_derivedD1Ev(%"struct.PR5529::A"* %this) unnamed_addr
+ // CHECK: define linkonce_odr void @_ZN6PR752617allocator_derivedD1Ev(%"struct.PR7526::allocator_derived"* %this) unnamed_addr
// CHECK-NOT: call void @__cxa_call_unexpected
// CHECK: }
void foo() {
@@ -145,10 +145,10 @@ namespace test1 {
P::~P() {} // CHECK: define void @_ZN5test11PD2Ev(%"struct.test1::P"* %this) unnamed_addr
struct Q : A, B { ~Q(); };
- Q::~Q() {} // CHECK: define void @_ZN5test11QD2Ev(%"struct.test1::M"* %this) unnamed_addr
+ Q::~Q() {} // CHECK: define void @_ZN5test11QD2Ev(%"struct.test1::Q"* %this) unnamed_addr
struct R : A { ~R(); };
- R::~R() { A a; } // CHECK: define void @_ZN5test11RD2Ev(%"struct.test1::M"* %this) unnamed_addr
+ R::~R() { A a; } // CHECK: define void @_ZN5test11RD2Ev(%"struct.test1::R"* %this) unnamed_addr
struct S : A { ~S(); int x; };
S::~S() {} // alias tested above
@@ -168,7 +168,7 @@ namespace test2 {
struct B : A { ~B(); };
B::~B() {}
- // CHECK: define void @_ZN5test21BD2Ev(%"struct.test1::M"* %this) unnamed_addr
+ // CHECK: define void @_ZN5test21BD2Ev(%"struct.test2::B"* %this) unnamed_addr
// CHECK: call void @_ZN5test21AD2Ev
}
@@ -233,28 +233,28 @@ namespace test4 {
namespace test5 {
struct A { ~A(); };
- // This is really unnecessarily verbose; we should be using phis,
- // even at -O0.
-
// CHECK: define void @_ZN5test53fooEv()
// CHECK: [[ELEMS:%.*]] = alloca [5 x [[A:%.*]]], align
- // CHECK-NEXT: [[IVAR:%.*]] = alloca i64
- // CHECK: [[ELEMSARRAY:%.*]] = bitcast [5 x [[A]]]* [[ELEMS]] to [[A]]
- // CHECK-NEXT: store i64 5, i64* [[IVAR]]
- // CHECK-NEXT: br label
- // CHECK: [[I:%.*]] = load i64* [[IVAR]]
- // CHECK-NEXT: icmp ne i64 [[I]], 0
- // CHECK-NEXT: br i1
- // CHECK: [[I:%.*]] = load i64* [[IVAR]]
- // CHECK-NEXT: [[I2:%.*]] = sub i64 [[I]], 1
- // CHECK-NEXT: getelementptr inbounds [[A]]* [[ELEMSARRAY]], i64 [[I2]]
- // CHECK-NEXT: call void @_ZN5test51AD1Ev(
- // CHECK-NEXT: br label
- // CHECK: [[I:%.*]] = load i64* [[IVAR]]
- // CHECK-NEXT: [[I1:%.*]] = sub i64 [[I]], 1
- // CHECK-NEXT: store i64 [[I1]], i64* [[IVAR]]
+ // CHECK-NEXT: [[EXN:%.*]] = alloca i8*
+ // CHECK-NEXT: [[SEL:%.*]] = alloca i32
+ // CHECK-NEXT: [[EHCLEANUP:%.*]] = alloca i32
+ // CHECK-NEXT: [[BEGIN:%.*]] = getelementptr inbounds [5 x [[A]]]* [[ELEMS]], i32 0, i32 0
+ // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [[A]]* [[BEGIN]], i64 5
// CHECK-NEXT: br label
+ // CHECK: [[POST:%.*]] = phi [[A]]* [ [[END]], {{%.*}} ], [ [[ELT:%.*]], {{%.*}} ]
+ // CHECK-NEXT: [[ELT]] = getelementptr inbounds [[A]]* [[POST]], i64 -1
+ // CHECK-NEXT: invoke void @_ZN5test51AD1Ev([[A]]* [[ELT]])
+ // CHECK: [[T0:%.*]] = icmp eq [[A]]* [[ELT]], [[BEGIN]]
+ // CHECK-NEXT: br i1 [[T0]],
// CHECK: ret void
+ // lpad
+ // CHECK: [[EMPTY:%.*]] = icmp eq [[A]]* [[BEGIN]], [[ELT]]
+ // CHECK-NEXT: br i1 [[EMPTY]]
+ // CHECK: [[AFTER:%.*]] = phi [[A]]* [ [[ELT]], {{%.*}} ], [ [[CUR:%.*]], {{%.*}} ]
+ // CHECK-NEXT: [[CUR:%.*]] = getelementptr inbounds [[A]]* [[AFTER]], i64 -1
+ // CHECK-NEXT: invoke void @_ZN5test51AD1Ev([[A]]* [[CUR]])
+ // CHECK: [[DONE:%.*]] = icmp eq [[A]]* [[CUR]], [[BEGIN]]
+ // CHECK-NEXT: br i1 [[DONE]],
void foo() {
A elems[5];
}
diff --git a/test/CodeGenCXX/eh.cpp b/test/CodeGenCXX/eh.cpp
index 44219b4f1754..58cb44515ddf 100644
--- a/test/CodeGenCXX/eh.cpp
+++ b/test/CodeGenCXX/eh.cpp
@@ -14,7 +14,7 @@ void test1() {
// CHECK-NEXT: [[EXN:%.*]] = bitcast i8* [[EXNOBJ]] to [[DSTAR:%[^*]*\*]]
// CHECK-NEXT: [[EXN2:%.*]] = bitcast [[DSTAR]] [[EXN]] to i8*
// CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[EXN2]], i8* bitcast ([[DSTAR]] @d1 to i8*), i64 8, i32 8, i1 false)
-// CHECK-NEXT: call void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast (%0* @_ZTI7test1_D to i8*), i8* null) noreturn
+// CHECK-NEXT: call void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast ({ i8*, i8* }* @_ZTI7test1_D to i8*), i8* null) noreturn
// CHECK-NEXT: unreachable
@@ -38,7 +38,7 @@ void test2() {
// CHECK-NEXT: invoke void @_ZN7test2_DC1ERKS_([[DSTAR]] [[EXN]], [[DSTAR]] @d2)
// CHECK-NEXT: to label %[[CONT:.*]] unwind label %{{.*}}
// : [[CONT]]: (can't check this in Release-Asserts builds)
-// CHECK: call void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast (%{{.*}}* @_ZTI7test2_D to i8*), i8* null) noreturn
+// CHECK: call void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast ({{.*}}* @_ZTI7test2_D to i8*), i8* null) noreturn
// CHECK-NEXT: unreachable
@@ -56,7 +56,7 @@ void test3() {
// CHECK: [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 8)
// CHECK-NEXT: [[EXN:%.*]] = bitcast i8* [[EXNOBJ]] to [[D:%[^*]+]]**
// CHECK-NEXT: store [[D]]* null, [[D]]** [[EXN]]
-// CHECK-NEXT: call void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast (%1* @_ZTIPV7test3_D to i8*), i8* null) noreturn
+// CHECK-NEXT: call void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast ({ i8*, i8*, i32, i8* }* @_ZTIPV7test3_D to i8*), i8* null) noreturn
// CHECK-NEXT: unreachable
@@ -84,10 +84,10 @@ namespace test5 {
// CHECK: [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 1)
// CHECK: [[EXNCAST:%.*]] = bitcast i8* [[EXNOBJ]] to [[A:%[^*]*]]*
// CHECK-NEXT: invoke void @_ZN5test51AC1Ev([[A]]* [[EXNCAST]])
-// CHECK: invoke void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast ({{%.*}}* @_ZTIN5test51AE to i8*), i8* bitcast (void ([[A]]*)* @_ZN5test51AD1Ev to i8*)) noreturn
+// CHECK: invoke void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast ({{.*}}* @_ZTIN5test51AE to i8*), i8* bitcast (void ([[A]]*)* @_ZN5test51AD1Ev to i8*)) noreturn
// CHECK-NEXT: to label {{%.*}} unwind label %[[HANDLER:[^ ]*]]
// : [[HANDLER]]: (can't check this in Release-Asserts builds)
-// CHECK: {{%.*}} = call i32 @llvm.eh.typeid.for(i8* bitcast ({{%.*}}* @_ZTIN5test51AE to i8*))
+// CHECK: {{%.*}} = call i32 @llvm.eh.typeid.for(i8* bitcast ({{.*}}* @_ZTIN5test51AE to i8*))
}
namespace test6 {
@@ -177,11 +177,11 @@ namespace test9 {
struct A { A(); };
- // CHECK: define void @_ZN5test91AC1Ev(%"struct.test10::A"* %this) unnamed_addr
+ // CHECK: define void @_ZN5test91AC1Ev(%"struct.test9::A"* %this) unnamed_addr
// CHECK: call void @_ZN5test91AC2Ev
// CHECK-NEXT: ret void
- // CHECK: define void @_ZN5test91AC2Ev(%"struct.test10::A"* %this) unnamed_addr
+ // CHECK: define void @_ZN5test91AC2Ev(%"struct.test9::A"* %this) unnamed_addr
A::A() try {
// CHECK: invoke void @_ZN5test96opaqueEv()
opaque();
diff --git a/test/CodeGenCXX/elide-call-reference.cpp b/test/CodeGenCXX/elide-call-reference.cpp
index c82eee70c840..55d30e24c102 100644
--- a/test/CodeGenCXX/elide-call-reference.cpp
+++ b/test/CodeGenCXX/elide-call-reference.cpp
@@ -7,5 +7,5 @@ void b() {
A x = a();
}
-// CHECK: call void @_ZN1AC1ERKS_
-// CHECK: call void @_ZN1AD1Ev
+// CHECK: call {{.*}} @_ZN1AC1ERKS_
+// CHECK: call {{.*}} @_ZN1AD1Ev
diff --git a/test/CodeGenCXX/for-range.cpp b/test/CodeGenCXX/for-range.cpp
index af4664462351..ab1a2317ba93 100644
--- a/test/CodeGenCXX/for-range.cpp
+++ b/test/CodeGenCXX/for-range.cpp
@@ -69,8 +69,8 @@ void for_range() {
A a;
for (B b : C()) {
// CHECK: call void @_ZN1CC1Ev(
- // CHECK: = call %struct.A* @_ZSt5beginR1C(
- // CHECK: = call %struct.A* @_ZSt3endR1C(
+ // CHECK: = call %struct.B* @_ZSt5beginR1C(
+ // CHECK: = call %struct.B* @_ZSt3endR1C(
// CHECK: br label %[[COND:.*]]
// CHECK: [[COND]]:
@@ -101,8 +101,8 @@ void for_member_range() {
A a;
for (B b : D()) {
// CHECK: call void @_ZN1DC1Ev(
- // CHECK: = call %struct.A* @_ZN1D5beginEv(
- // CHECK: = call %struct.A* @_ZN1D3endEv(
+ // CHECK: = call %struct.B* @_ZN1D5beginEv(
+ // CHECK: = call %struct.B* @_ZN1D3endEv(
// CHECK: br label %[[COND:.*]]
// CHECK: [[COND]]:
diff --git a/test/CodeGenCXX/global-init.cpp b/test/CodeGenCXX/global-init.cpp
index 9bd7390d076c..053210bdfbec 100644
--- a/test/CodeGenCXX/global-init.cpp
+++ b/test/CodeGenCXX/global-init.cpp
@@ -21,21 +21,21 @@ struct D { ~D(); };
// PR6205: The casts should not require global initializers
// CHECK: @_ZN6PR59741cE = external global %"struct.PR5974::C"
// CHECK: @_ZN6PR59741aE = global %"struct.PR5974::A"* getelementptr inbounds (%"struct.PR5974::C"* @_ZN6PR59741cE, i32 0, i32 0)
-// CHECK: @_ZN6PR59741bE = global %"struct.PR5974::A"* bitcast (i8* getelementptr (i8* bitcast (%"struct.PR5974::C"* @_ZN6PR59741cE to i8*), i64 4) to %"struct.PR5974::A"*), align 8
+// CHECK: @_ZN6PR59741bE = global %"struct.PR5974::B"* bitcast (i8* getelementptr (i8* bitcast (%"struct.PR5974::C"* @_ZN6PR59741cE to i8*), i64 4) to %"struct.PR5974::B"*), align 8
// CHECK: call void @_ZN1AC1Ev(%struct.A* @a)
// CHECK: call i32 @__cxa_atexit(void (i8*)* bitcast (void (%struct.A*)* @_ZN1AD1Ev to void (i8*)*), i8* getelementptr inbounds (%struct.A* @a, i32 0, i32 0), i8* bitcast (i8** @__dso_handle to i8*))
A a;
-// CHECK: call void @_ZN1BC1Ev(%struct.A* @b)
-// CHECK: call i32 @__cxa_atexit(void (i8*)* bitcast (void (%struct.A*)* @_ZN1BD1Ev to void (i8*)*), i8* getelementptr inbounds (%struct.A* @b, i32 0, i32 0), i8* bitcast (i8** @__dso_handle to i8*))
+// CHECK: call void @_ZN1BC1Ev(%struct.B* @b)
+// CHECK: call i32 @__cxa_atexit(void (i8*)* bitcast (void (%struct.B*)* @_ZN1BD1Ev to void (i8*)*), i8* getelementptr inbounds (%struct.B* @b, i32 0, i32 0), i8* bitcast (i8** @__dso_handle to i8*))
B b;
// PR6205: this should not require a global initializer
// CHECK-NOT: call void @_ZN1CC1Ev(%struct.C* @c)
C c;
-// CHECK: call i32 @__cxa_atexit(void (i8*)* bitcast (void (%struct.A*)* @_ZN1DD1Ev to void (i8*)*), i8* getelementptr inbounds (%struct.A* @d, i32 0, i32 0), i8* bitcast (i8** @__dso_handle to i8*))
+// CHECK: call i32 @__cxa_atexit(void (i8*)* bitcast (void (%struct.D*)* @_ZN1DD1Ev to void (i8*)*), i8* getelementptr inbounds (%struct.D* @d, i32 0, i32 0), i8* bitcast (i8** @__dso_handle to i8*))
D d;
// <rdar://problem/7458115>
@@ -70,6 +70,20 @@ namespace test3 {
const char *test() { return var; }
}
+namespace test6 {
+ struct A {
+ A();
+ };
+ extern int foo();
+
+ // This needs an initialization function and guard variables.
+ // CHECK: load i8* bitcast (i64* @_ZGVN5test61xE
+ // CHECK: [[CALL:%.*]] = call i32 @_ZN5test63fooEv
+ // CHECK-NEXT: store i32 [[CALL]], i32* @_ZN5test61xE
+ // CHECK-NEXT: store i64 1, i64* @_ZGVN5test61xE
+ __attribute__((weak)) int x = foo();
+}
+
namespace PR5974 {
struct A { int a; };
struct B { int b; };
@@ -97,15 +111,6 @@ namespace test5 {
};
}
-namespace test6 {
- struct A {
- A();
- };
- extern int foo();
-
- // This needs an initialization function but not guard variables.
- __attribute__((weak)) int x = foo();
-}
// At the end of the file, we check that y is initialized before z.
diff --git a/test/CodeGenCXX/implicit-copy-constructor.cpp b/test/CodeGenCXX/implicit-copy-constructor.cpp
index 500860182ecc..8bc84a534b36 100644
--- a/test/CodeGenCXX/implicit-copy-constructor.cpp
+++ b/test/CodeGenCXX/implicit-copy-constructor.cpp
@@ -70,3 +70,13 @@ void test_X2()
pimpl pdata;
pdata.f0( new impl(*i));
}
+
+// rdar://problem/9598341
+namespace test3 {
+ struct A { A(const A&); A&operator=(const A&); };
+ struct B { A a; unsigned : 0; };
+ void test(const B &x) {
+ B y = x;
+ y = x;
+ }
+}
diff --git a/test/CodeGenCXX/init-incomplete-type.cpp b/test/CodeGenCXX/init-incomplete-type.cpp
index 3312d3e04b71..1755dfb7beb1 100644
--- a/test/CodeGenCXX/init-incomplete-type.cpp
+++ b/test/CodeGenCXX/init-incomplete-type.cpp
@@ -10,3 +10,22 @@ static struct Bar<int> bar[1] = {
{ 0 }
};
+
+
+namespace incomplete_type_refs {
+ struct A;
+ extern A g[];
+ void foo(A*);
+ void f(void) {
+ foo(g); // Reference to array with unknown element type.
+ }
+
+ struct A { // define the element type.
+ int a,b,c;
+ };
+
+ A *f2() {
+ return &g[1];
+ }
+
+} \ No newline at end of file
diff --git a/test/CodeGenCXX/mangle-subst-std.cpp b/test/CodeGenCXX/mangle-subst-std.cpp
index 837d4fa8570d..30b579ceb823 100644
--- a/test/CodeGenCXX/mangle-subst-std.cpp
+++ b/test/CodeGenCXX/mangle-subst-std.cpp
@@ -15,8 +15,8 @@
namespace std {
struct A { A(); };
- // CHECK: define void @_ZNSt1AC1Ev(%"struct.N::std::A"* %this) unnamed_addr
- // CHECK: define void @_ZNSt1AC2Ev(%"struct.N::std::A"* %this) unnamed_addr
+ // CHECK: define void @_ZNSt1AC1Ev(%"struct.std::A"* %this) unnamed_addr
+ // CHECK: define void @_ZNSt1AC2Ev(%"struct.std::A"* %this) unnamed_addr
A::A() { }
};
diff --git a/test/CodeGenCXX/mangle-template.cpp b/test/CodeGenCXX/mangle-template.cpp
index 463f15dc4abe..f95e1521549d 100644
--- a/test/CodeGenCXX/mangle-template.cpp
+++ b/test/CodeGenCXX/mangle-template.cpp
@@ -82,7 +82,7 @@ namespace test7 {
X(U*, typename int_c<(meta<T>::value + meta<U>::value)>::type *) { }
};
- // CHECK: define weak_odr void @_ZN5test71XIiEC1IdEEPT_PNS_5int_cIXplL_ZNS_4metaIiE5valueEEsrNS6_IS3_EE5valueEE4typeE(%"class.test1::T"* %this, double*, float*) unnamed_addr
+ // CHECK: define weak_odr {{.*}} @_ZN5test71XIiEC1IdEEPT_PNS_5int_cIXplL_ZNS_4metaIiE5valueEEsr4metaIS3_EE5valueEE4typeE(%"struct.test7::X"* %this, double*, float*) unnamed_addr
template X<int>::X(double*, float*);
}
@@ -101,7 +101,7 @@ namespace test8 {
template<typename T>
void f(int_c<meta<T>::type::value>) { }
- // CHECK: define weak_odr void @_ZN5test81fIiEEvNS_5int_cIXsrNS_4metaIT_E4typeE5valueEEE
+ // CHECK: define weak_odr void @_ZN5test81fIiEEvNS_5int_cIXsr4metaIT_E4typeE5valueEEE
template void f<int>(int_c<sizeof(int)>);
}
diff --git a/test/CodeGenCXX/mangle.cpp b/test/CodeGenCXX/mangle.cpp
index 01dcf8b2305a..453b7b713ac6 100644
--- a/test/CodeGenCXX/mangle.cpp
+++ b/test/CodeGenCXX/mangle.cpp
@@ -196,9 +196,9 @@ template<typename T> struct __enable_if<true, T> {
// PR5063
template<typename T> typename __enable_if<__is_scalar_type<T>::__value, void>::__type ft7() { }
-// CHECK: @_Z3ft7IiEN11__enable_ifIXsr16__is_scalar_typeIT_E7__valueEvE6__typeEv
+// CHECK: @_Z3ft7IiEN11__enable_ifIXsr16__is_scalar_typeIT_EE7__valueEvE6__typeEv
template void ft7<int>();
-// CHECK: @_Z3ft7IPvEN11__enable_ifIXsr16__is_scalar_typeIT_E7__valueEvE6__typeEv
+// CHECK: @_Z3ft7IPvEN11__enable_ifIXsr16__is_scalar_typeIT_EE7__valueEvE6__typeEv
template void ft7<void*>();
// PR5144
@@ -226,9 +226,9 @@ S7::S7() {}
// PR5063
template<typename T> typename __enable_if<(__is_scalar_type<T>::__value), void>::__type ft8() { }
-// CHECK: @_Z3ft8IiEN11__enable_ifIXsr16__is_scalar_typeIT_E7__valueEvE6__typeEv
+// CHECK: @_Z3ft8IiEN11__enable_ifIXsr16__is_scalar_typeIT_EE7__valueEvE6__typeEv
template void ft8<int>();
-// CHECK: @_Z3ft8IPvEN11__enable_ifIXsr16__is_scalar_typeIT_E7__valueEvE6__typeEv
+// CHECK: @_Z3ft8IPvEN11__enable_ifIXsr16__is_scalar_typeIT_EE7__valueEvE6__typeEv
template void ft8<void*>();
// PR5796
@@ -241,7 +241,7 @@ template<bool, typename> struct __enable_if {};
template<typename T> struct __enable_if<true, T> { typedef T __type; };
template<typename T>
-// CHECK: define linkonce_odr void @_ZN6PR57968__fill_aIiEENS_11__enable_ifIXntsrNS_16__is_scalar_typeIT_EE7__valueEvE6__typeEv
+// CHECK: define linkonce_odr void @_ZN6PR57968__fill_aIiEENS_11__enable_ifIXntsr16__is_scalar_typeIT_EE7__valueEvE6__typeEv
typename __enable_if<!__is_scalar_type<T>::__value, void>::__type __fill_a() { };
void f() { __fill_a<int>(); }
@@ -711,3 +711,150 @@ namespace test27 {
b<A>(f);
}
}
+
+// An injected class name type in a unresolved-name.
+namespace test28 {
+ template <class T> struct A {
+ enum { bit };
+ };
+
+ template <class T> void foo(decltype(A<T>::A::bit) x);
+
+ void test() {
+ foo<char>(A<char>::bit);
+ // CHECK: call void @_ZN6test283fooIcEEvDtsr1AIT_E1AE3bitE(
+ }
+}
+
+// An enclosing template type parameter in an unresolved-name.
+namespace test29 {
+ template <class T> struct A {
+ template <class U> static void foo(decltype(T::fn(U())) x);
+ };
+ struct B { static int fn(int); static long fn(long); };
+
+ void test() {
+ A<B>::foo<int>(0);
+ // CHECK: call void @_ZN6test291AINS_1BEE3fooIiEEvDTclsrS1_2fncvT__EEE(
+ }
+}
+
+// An enclosing template template parameter in an unresolved-name.
+namespace test30 {
+ template <template <class> class T> struct A {
+ template <class U> static void foo(decltype(T<U>::fn()) x);
+ };
+ template <class T> struct B { static T fn(); };
+
+ void test() {
+ A<B>::foo<int>(0);
+ // CHECK: call void @_ZN6test301AINS_1BEE3fooIiEEvDTclsrS1_IT_EE2fnEE(
+ }
+}
+
+namespace test31 { // instantiation-dependent mangling of decltype
+ int x;
+ template<class T> auto f1(T p)->decltype(x) { return 0; }
+ // The return type in the mangling of the template signature
+ // is encoded as "i".
+ template<class T> auto f2(T p)->decltype(p) { return 0; }
+ // The return type in the mangling of the template signature
+ // is encoded as "Dtfp_E".
+ void g(int);
+ template<class T> auto f3(T p)->decltype(g(p)) {}
+
+ // CHECK: define weak_odr i32 @_ZN6test312f1IiEEiT_(
+ template int f1(int);
+ // CHECK: define weak_odr i32 @_ZN6test312f2IiEEDtfp_ET_
+ template int f2(int);
+ // CHECK: define weak_odr void @_ZN6test312f3IiEEDTcl1gfp_EET_
+ template void f3(int);
+}
+
+// PR10205
+namespace test32 {
+ template<typename T, int=T::value> struct A {
+ typedef int type;
+ };
+ struct B { enum { value = 4 }; };
+
+ template <class T> typename A<T>::type foo() { return 0; }
+ void test() {
+ foo<B>();
+ // CHECK: call i32 @_ZN6test323fooINS_1BEEENS_1AIT_XsrS3_5valueEE4typeEv()
+ }
+}
+
+namespace test33 {
+ template <class T> struct X {
+ enum { value = T::value };
+ };
+
+ template<typename T, int=X<T>::value> struct A {
+ typedef int type;
+ };
+ struct B { enum { value = 4 }; };
+
+ template <class T> typename A<T>::type foo() { return 0; }
+
+ void test() {
+ foo<B>();
+ // CHECK: call i32 @_ZN6test333fooINS_1BEEENS_1AIT_Xsr1XIS3_EE5valueEE4typeEv()
+ }
+}
+
+namespace test34 {
+ // Mangling for instantiation-dependent decltype expressions.
+ template<typename T>
+ void f(decltype(sizeof(decltype(T() + T())))) {}
+
+ // CHECK: define weak_odr void @_ZN6test341fIiEEvDTstDTplcvT__EcvS1__EEE
+ template void f<int>(decltype(sizeof(1)));
+
+ // Mangling for non-instantiation-dependent sizeof expressions.
+ template<unsigned N>
+ void f2(int (&)[N + sizeof(int*)]) {}
+
+ // CHECK: define weak_odr void @_ZN6test342f2ILj4EEEvRAplT_Lm8E_i
+ template void f2<4>(int (&)[4 + sizeof(int*)]);
+
+ // Mangling for non-instantiation-dependent sizeof expressions
+ // involving an implicit conversion of the result of the sizeof.
+ template<unsigned long long N>
+ void f3(int (&)[N + sizeof(int*)]) {}
+
+ // CHECK: define weak_odr void @_ZN6test342f3ILy4EEEvRAplT_Ly8E_i
+ template void f3<4>(int (&)[4 + sizeof(int*)]);
+
+ // Mangling for instantiation-dependent sizeof() expressions as
+ // template arguments.
+ template<unsigned> struct A { };
+
+ template<typename T> void f4(::test34::A<sizeof(sizeof(decltype(T() + T())))>) { }
+
+ // CHECK: define weak_odr void @_ZN6test342f4IiEEvNS_1AIXszstDTplcvT__EcvS2__EEEEE
+ template void f4<int>(A<sizeof(sizeof(int))>);
+}
+
+namespace test35 {
+ // Dependent operator names of unknown arity.
+ struct A {
+ template<typename U> A operator+(U) const;
+ };
+
+ template<typename T>
+ void f1(decltype(sizeof(&T::template operator+<int>))) {}
+
+ // CHECK: define weak_odr void @_ZN6test352f1INS_1AEEEvDTszadsrT_plIiEE
+ template void f1<A>(__SIZE_TYPE__);
+}
+
+namespace test36 {
+ template<unsigned> struct A { };
+
+ template<typename ...Types>
+ auto f1(Types... values) -> A<sizeof...(values)> { }
+
+ // CHECK: define weak_odr {{.*}} @_ZN6test362f1IJifEEENS_1AIXsZfp_EEEDpT_
+ template A<2> f1(int, float);
+}
diff --git a/test/CodeGenCXX/member-function-pointers.cpp b/test/CodeGenCXX/member-function-pointers.cpp
index 011e9cd68556..4c42bd8283ae 100644
--- a/test/CodeGenCXX/member-function-pointers.cpp
+++ b/test/CodeGenCXX/member-function-pointers.cpp
@@ -11,56 +11,56 @@ void (A::*volatile vpa)();
void (B::*pb)();
void (C::*pc)();
-// CHECK: @pa2 = global %0 { i64 ptrtoint (void (%struct.A*)* @_ZN1A1fEv to i64), i64 0 }, align 8
+// CHECK: @pa2 = global { i64, i64 } { i64 ptrtoint (void (%struct.A*)* @_ZN1A1fEv to i64), i64 0 }, align 8
void (A::*pa2)() = &A::f;
-// CHECK: @pa3 = global %0 { i64 1, i64 0 }, align 8
-// CHECK-LP32: @pa3 = global %0 { i32 1, i32 0 }, align 4
+// CHECK: @pa3 = global { i64, i64 } { i64 1, i64 0 }, align 8
+// CHECK-LP32: @pa3 = global { i32, i32 } { i32 1, i32 0 }, align 4
void (A::*pa3)() = &A::vf1;
-// CHECK: @pa4 = global %0 { i64 9, i64 0 }, align 8
-// CHECK-LP32: @pa4 = global %0 { i32 5, i32 0 }, align 4
+// CHECK: @pa4 = global { i64, i64 } { i64 9, i64 0 }, align 8
+// CHECK-LP32: @pa4 = global { i32, i32 } { i32 5, i32 0 }, align 4
void (A::*pa4)() = &A::vf2;
-// CHECK: @pc2 = global %0 { i64 ptrtoint (void (%struct.A*)* @_ZN1A1fEv to i64), i64 16 }, align 8
+// CHECK: @pc2 = global { i64, i64 } { i64 ptrtoint (void (%struct.A*)* @_ZN1A1fEv to i64), i64 16 }, align 8
void (C::*pc2)() = &C::f;
-// CHECK: @pc3 = global %0 { i64 1, i64 0 }, align 8
+// CHECK: @pc3 = global { i64, i64 } { i64 1, i64 0 }, align 8
void (A::*pc3)() = &A::vf1;
void f() {
- // CHECK: store %0 zeroinitializer, %0* @pa
+ // CHECK: store { i64, i64 } zeroinitializer, { i64, i64 }* @pa
pa = 0;
// Is this okay? What are LLVM's volatile semantics for structs?
- // CHECK: volatile store %0 zeroinitializer, %0* @vpa
+ // CHECK: volatile store { i64, i64 } zeroinitializer, { i64, i64 }* @vpa
vpa = 0;
- // CHECK: [[TMP:%.*]] = load %0* @pa, align 8
- // CHECK: [[TMPADJ:%.*]] = extractvalue %0 [[TMP]], 1
+ // CHECK: [[TMP:%.*]] = load { i64, i64 }* @pa, align 8
+ // CHECK: [[TMPADJ:%.*]] = extractvalue { i64, i64 } [[TMP]], 1
// CHECK: [[ADJ:%.*]] = add nsw i64 [[TMPADJ]], 16
- // CHECK: [[RES:%.*]] = insertvalue %0 [[TMP]], i64 [[ADJ]], 1
- // CHECK: store %0 [[RES]], %0* @pc, align 8
+ // CHECK: [[RES:%.*]] = insertvalue { i64, i64 } [[TMP]], i64 [[ADJ]], 1
+ // CHECK: store { i64, i64 } [[RES]], { i64, i64 }* @pc, align 8
pc = pa;
- // CHECK: [[TMP:%.*]] = load %0* @pc, align 8
- // CHECK: [[TMPADJ:%.*]] = extractvalue %0 [[TMP]], 1
+ // CHECK: [[TMP:%.*]] = load { i64, i64 }* @pc, align 8
+ // CHECK: [[TMPADJ:%.*]] = extractvalue { i64, i64 } [[TMP]], 1
// CHECK: [[ADJ:%.*]] = sub nsw i64 [[TMPADJ]], 16
- // CHECK: [[RES:%.*]] = insertvalue %0 [[TMP]], i64 [[ADJ]], 1
- // CHECK: store %0 [[RES]], %0* @pa, align 8
+ // CHECK: [[RES:%.*]] = insertvalue { i64, i64 } [[TMP]], i64 [[ADJ]], 1
+ // CHECK: store { i64, i64 } [[RES]], { i64, i64 }* @pa, align 8
pa = static_cast<void (A::*)()>(pc);
}
void f2() {
- // CHECK: store %0 { i64 ptrtoint (void (%struct.A*)* @_ZN1A1fEv to i64), i64 0 }
+ // CHECK: store { i64, i64 } { i64 ptrtoint (void (%struct.A*)* @_ZN1A1fEv to i64), i64 0 }
void (A::*pa2)() = &A::f;
- // CHECK: store %0 { i64 1, i64 0 }
- // CHECK-LP32: store %0 { i32 1, i32 0 }
+ // CHECK: store { i64, i64 } { i64 1, i64 0 }
+ // CHECK-LP32: store { i32, i32 } { i32 1, i32 0 }
void (A::*pa3)() = &A::vf1;
- // CHECK: store %0 { i64 9, i64 0 }
- // CHECK-LP32: store %0 { i32 5, i32 0 }
+ // CHECK: store { i64, i64 } { i64 9, i64 0 }
+ // CHECK-LP32: store { i32, i32 } { i32 5, i32 0 }
void (A::*pa4)() = &A::vf2;
}
diff --git a/test/CodeGenCXX/member-init-assignment.cpp b/test/CodeGenCXX/member-init-assignment.cpp
index 128cb888f3d4..84c4a36fe2db 100644
--- a/test/CodeGenCXX/member-init-assignment.cpp
+++ b/test/CodeGenCXX/member-init-assignment.cpp
@@ -10,8 +10,8 @@ struct Foo {
Foo::Foo(unsigned arg) : file_id(arg = 42)
{ }
-// CHECK: define void @_ZN3FooC2Ej(%struct.Foo* %this, i32 %arg) unnamed_addr
+// CHECK: define {{.*}} @_ZN3FooC2Ej(%struct.Foo* %this, i32 %arg) unnamed_addr
// CHECK: [[ARG:%.*]] = alloca i32
// CHECK: store i32 42, i32* [[ARG]]
// CHECK: store i32 42, i32* %{{.*}}
-// CHECK: ret void
+// CHECK: ret {{void|%struct.Foo}}
diff --git a/test/CodeGenCXX/member-init-ctor.cpp b/test/CodeGenCXX/member-init-ctor.cpp
index d9a6734b319b..d70947bcab00 100644
--- a/test/CodeGenCXX/member-init-ctor.cpp
+++ b/test/CodeGenCXX/member-init-ctor.cpp
@@ -7,7 +7,7 @@ struct S {
S s;
-// CHECK: define{{.*}} void @_ZN1SC2Ev(
+// CHECK: define {{.*}} @_ZN1SC2Ev(
// CHECK-NOT }
// CHECK: call {{.*}} @_Z1bv()
// CHECK-NOT }
diff --git a/test/CodeGenCXX/new-overflow.cpp b/test/CodeGenCXX/new-overflow.cpp
new file mode 100644
index 000000000000..68f89c35b636
--- /dev/null
+++ b/test/CodeGenCXX/new-overflow.cpp
@@ -0,0 +1,209 @@
+// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm -o - | FileCheck %s
+
+// rdar://problem/9246208
+
+// Basic test.
+namespace test0 {
+ struct A {
+ A();
+ int x;
+ };
+
+ typedef A elt;
+
+ // CHECK: define [[A:%.*]]* @_ZN5test04testEs(i16 signext
+ // CHECK: [[N:%.*]] = sext i16 {{%.*}} to i32
+ // CHECK-NEXT: [[T0:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[N]], i32 4)
+ // CHECK-NEXT: [[T1:%.*]] = extractvalue { i32, i1 } [[T0]], 1
+ // CHECK-NEXT: [[T2:%.*]] = extractvalue { i32, i1 } [[T0]], 0
+ // CHECK-NEXT: [[T3:%.*]] = select i1 [[T1]], i32 -1, i32 [[T2]]
+ // CHECK-NEXT: call noalias i8* @_Znaj(i32 [[T3]])
+ // CHECK: getelementptr inbounds {{.*}}, i32 [[N]]
+ elt *test(short s) {
+ return new elt[s];
+ }
+}
+
+// test0 with a nested array.
+namespace test1 {
+ struct A {
+ A();
+ int x;
+ };
+
+ typedef A elt[100];
+
+ // CHECK: define [100 x [[A:%.*]]]* @_ZN5test14testEs(i16 signext
+ // CHECK: [[N:%.*]] = sext i16 {{%.*}} to i32
+ // CHECK-NEXT: [[T0:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[N]], i32 400)
+ // CHECK-NEXT: [[T1:%.*]] = extractvalue { i32, i1 } [[T0]], 1
+ // CHECK-NEXT: [[T2:%.*]] = extractvalue { i32, i1 } [[T0]], 0
+ // CHECK-NEXT: [[T3:%.*]] = mul i32 [[N]], 100
+ // CHECK-NEXT: [[T4:%.*]] = select i1 [[T1]], i32 -1, i32 [[T2]]
+ // CHECK-NEXT: call noalias i8* @_Znaj(i32 [[T4]])
+ // CHECK: getelementptr inbounds {{.*}}, i32 [[T3]]
+ elt *test(short s) {
+ return new elt[s];
+ }
+}
+
+// test1 with an array cookie.
+namespace test2 {
+ struct A {
+ A();
+ ~A();
+ int x;
+ };
+
+ typedef A elt[100];
+
+ // CHECK: define [100 x [[A:%.*]]]* @_ZN5test24testEs(i16 signext
+ // CHECK: [[N:%.*]] = sext i16 {{%.*}} to i32
+ // CHECK-NEXT: [[T0:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[N]], i32 400)
+ // CHECK-NEXT: [[T1:%.*]] = extractvalue { i32, i1 } [[T0]], 1
+ // CHECK-NEXT: [[T2:%.*]] = extractvalue { i32, i1 } [[T0]], 0
+ // CHECK-NEXT: [[T3:%.*]] = mul i32 [[N]], 100
+ // CHECK-NEXT: [[T4:%.*]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[T2]], i32 4)
+ // CHECK-NEXT: [[T5:%.*]] = extractvalue { i32, i1 } [[T4]], 1
+ // CHECK-NEXT: [[T6:%.*]] = or i1 [[T1]], [[T5]]
+ // CHECK-NEXT: [[T7:%.*]] = extractvalue { i32, i1 } [[T4]], 0
+ // CHECK-NEXT: [[T8:%.*]] = select i1 [[T6]], i32 -1, i32 [[T7]]
+ // CHECK-NEXT: call noalias i8* @_Znaj(i32 [[T8]])
+ // CHECK: getelementptr inbounds {{.*}}, i32 [[T3]]
+ elt *test(short s) {
+ return new elt[s];
+ }
+}
+
+// test0 with a 1-byte element.
+namespace test4 {
+ struct A {
+ A();
+ };
+
+ typedef A elt;
+
+ // CHECK: define [[A:%.*]]* @_ZN5test44testEs(i16 signext
+ // CHECK: [[N:%.*]] = sext i16 {{%.*}} to i32
+ // CHECK-NEXT: [[T0:%.*]] = icmp slt i32 [[N]], 0
+ // CHECK-NEXT: [[T1:%.*]] = select i1 [[T0]], i32 -1, i32 [[N]]
+ // CHECK-NEXT: call noalias i8* @_Znaj(i32 [[T1]])
+ // CHECK: getelementptr inbounds {{.*}}, i32 [[N]]
+ elt *test(short s) {
+ return new elt[s];
+ }
+}
+
+// test4 with no sext required.
+namespace test5 {
+ struct A {
+ A();
+ };
+
+ typedef A elt;
+
+ // CHECK: define [[A:%.*]]* @_ZN5test54testEi(i32
+ // CHECK: [[N:%.*]] = load i32*
+ // CHECK-NEXT: [[T0:%.*]] = icmp slt i32 [[N]], 0
+ // CHECK-NEXT: [[T1:%.*]] = select i1 [[T0]], i32 -1, i32 [[N]]
+ // CHECK-NEXT: call noalias i8* @_Znaj(i32 [[T1]])
+ // CHECK: getelementptr inbounds {{.*}}, i32 [[N]]
+ elt *test(int s) {
+ return new elt[s];
+ }
+}
+
+// test0 with an unsigned size.
+namespace test6 {
+ struct A {
+ A();
+ int x;
+ };
+
+ typedef A elt;
+
+ // CHECK: define [[A:%.*]]* @_ZN5test64testEt(i16 zeroext
+ // CHECK: [[N:%.*]] = zext i16 {{%.*}} to i32
+ // CHECK-NEXT: [[T0:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[N]], i32 4)
+ // CHECK-NEXT: [[T1:%.*]] = extractvalue { i32, i1 } [[T0]], 1
+ // CHECK-NEXT: [[T2:%.*]] = extractvalue { i32, i1 } [[T0]], 0
+ // CHECK-NEXT: [[T3:%.*]] = select i1 [[T1]], i32 -1, i32 [[T2]]
+ // CHECK-NEXT: call noalias i8* @_Znaj(i32 [[T3]])
+ // CHECK: getelementptr inbounds {{.*}}, i32 [[N]]
+ elt *test(unsigned short s) {
+ return new elt[s];
+ }
+}
+
+// test1 with an unsigned size.
+namespace test7 {
+ struct A {
+ A();
+ int x;
+ };
+
+ typedef A elt[100];
+
+ // CHECK: define [100 x [[A:%.*]]]* @_ZN5test74testEt(i16 zeroext
+ // CHECK: [[N:%.*]] = zext i16 {{%.*}} to i32
+ // CHECK-NEXT: [[T0:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[N]], i32 400)
+ // CHECK-NEXT: [[T1:%.*]] = extractvalue { i32, i1 } [[T0]], 1
+ // CHECK-NEXT: [[T2:%.*]] = extractvalue { i32, i1 } [[T0]], 0
+ // CHECK-NEXT: [[T3:%.*]] = mul i32 [[N]], 100
+ // CHECK-NEXT: [[T4:%.*]] = select i1 [[T1]], i32 -1, i32 [[T2]]
+ // CHECK-NEXT: call noalias i8* @_Znaj(i32 [[T4]])
+ // CHECK: getelementptr inbounds {{.*}}, i32 [[T3]]
+ elt *test(unsigned short s) {
+ return new elt[s];
+ }
+}
+
+// test0 with a signed type larger than size_t.
+namespace test8 {
+ struct A {
+ A();
+ int x;
+ };
+
+ typedef A elt;
+
+ // CHECK: define [[A:%.*]]* @_ZN5test84testEx(i64
+ // CHECK: [[N:%.*]] = load i64*
+ // CHECK-NEXT: [[T0:%.*]] = icmp uge i64 [[N]], 4294967296
+ // CHECK-NEXT: [[T1:%.*]] = trunc i64 [[N]] to i32
+ // CHECK-NEXT: [[T2:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[T1]], i32 4)
+ // CHECK-NEXT: [[T3:%.*]] = extractvalue { i32, i1 } [[T2]], 1
+ // CHECK-NEXT: [[T4:%.*]] = or i1 [[T0]], [[T3]]
+ // CHECK-NEXT: [[T5:%.*]] = extractvalue { i32, i1 } [[T2]], 0
+ // CHECK-NEXT: [[T6:%.*]] = select i1 [[T4]], i32 -1, i32 [[T5]]
+ // CHECK-NEXT: call noalias i8* @_Znaj(i32 [[T6]])
+ // CHECK: getelementptr inbounds {{.*}}, i32 [[T1]]
+ elt *test(long long s) {
+ return new elt[s];
+ }
+}
+
+// test8 with an unsigned type.
+namespace test9 {
+ struct A {
+ A();
+ int x;
+ };
+
+ typedef A elt;
+
+ // CHECK: define [[A:%.*]]* @_ZN5test94testEy(i64
+ // CHECK: [[N:%.*]] = load i64*
+ // CHECK-NEXT: [[T0:%.*]] = icmp uge i64 [[N]], 4294967296
+ // CHECK-NEXT: [[T1:%.*]] = trunc i64 [[N]] to i32
+ // CHECK-NEXT: [[T2:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[T1]], i32 4)
+ // CHECK-NEXT: [[T3:%.*]] = extractvalue { i32, i1 } [[T2]], 1
+ // CHECK-NEXT: [[T4:%.*]] = or i1 [[T0]], [[T3]]
+ // CHECK-NEXT: [[T5:%.*]] = extractvalue { i32, i1 } [[T2]], 0
+ // CHECK-NEXT: [[T6:%.*]] = select i1 [[T4]], i32 -1, i32 [[T5]]
+ // CHECK-NEXT: call noalias i8* @_Znaj(i32 [[T6]])
+ // CHECK: getelementptr inbounds {{.*}}, i32 [[T1]]
+ elt *test(unsigned long long s) {
+ return new elt[s];
+ }
+}
diff --git a/test/CodeGenCXX/new.cpp b/test/CodeGenCXX/new.cpp
index d14a5e251ce0..3a72bb84e7f6 100644
--- a/test/CodeGenCXX/new.cpp
+++ b/test/CodeGenCXX/new.cpp
@@ -182,12 +182,17 @@ namespace test15 {
}
// CHECK: define void @_ZN6test155test1EPv(
- // CHECK: [[P:%.*]] = load i8*
+ // CHECK: [[P:%.*]] = load i8**
// CHECK-NEXT: icmp eq i8* [[P]], null
// CHECK-NEXT: br i1
- // CHECK: [[T0:%.*]] = bitcast i8* [[P]] to [[A:%.*]]*
- // CHECK: [[T1:%.*]] = getelementptr inbounds [[A]]* [[T0]],
- // CHECK-NEXT: call void @_ZN6test151AC1Ev([[A]]* [[T1]])
+ // CHECK: [[BEGIN:%.*]] = bitcast i8* [[P]] to [[A:%.*]]*
+ // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [[A]]* [[BEGIN]], i64 5
+ // CHECK-NEXT: br label
+ // CHECK: [[CUR:%.*]] = phi [[A]]* [ [[BEGIN]], {{%.*}} ], [ [[NEXT:%.*]], {{%.*}} ]
+ // CHECK-NEXT: call void @_ZN6test151AC1Ev([[A]]* [[CUR]])
+ // CHECK-NEXT: [[NEXT]] = getelementptr inbounds [[A]]* [[CUR]], i64 1
+ // CHECK-NEXT: [[DONE:%.*]] = icmp eq [[A]]* [[NEXT]], [[END]]
+ // CHECK-NEXT: br i1 [[DONE]]
void test1(void *p) {
new (p) A[5];
}
@@ -202,10 +207,27 @@ namespace test15 {
// CHECK-NEXT: [[P:%.*]] = load i8*
// CHECK-NEXT: icmp eq i8* [[P]], null
// CHECK-NEXT: br i1
- // CHECK: [[T0:%.*]] = bitcast i8* [[P]] to [[A:%.*]]*
- // CHECK: [[T1:%.*]] = getelementptr inbounds [[A]]* [[T0]],
- // CHECK-NEXT: call void @_ZN6test151AC1Ev([[A]]* [[T1]])
+ // CHECK: [[BEGIN:%.*]] = bitcast i8* [[P]] to [[A:%.*]]*
+ // CHECK-NEXT: [[ISEMPTY:%.*]] = icmp eq i64 [[T0]], 0
+ // CHECK-NEXT: br i1 [[ISEMPTY]],
+ // CHECK: [[END:%.*]] = getelementptr inbounds [[A]]* [[BEGIN]], i64 [[T0]]
+ // CHECK-NEXT: br label
+ // CHECK: [[CUR:%.*]] = phi [[A]]* [ [[BEGIN]],
+ // CHECK-NEXT: call void @_ZN6test151AC1Ev([[A]]* [[CUR]])
void test2(void *p, int n) {
new (p) A[n];
}
}
+
+namespace PR10197 {
+ // CHECK: define weak_odr void @_ZN7PR101971fIiEEvv()
+ template<typename T>
+ void f() {
+ // CHECK: [[CALL:%.*]] = call noalias i8* @_Znwm
+ // CHECK-NEXT: [[CASTED:%.*]] = bitcast i8* [[CALL]] to
+ new T;
+ // CHECK-NEXT: ret void
+ }
+
+ template void f<int>();
+}
diff --git a/test/CodeGenCXX/noinline-template.cpp b/test/CodeGenCXX/noinline-template.cpp
new file mode 100644
index 000000000000..6ee3935bc041
--- /dev/null
+++ b/test/CodeGenCXX/noinline-template.cpp
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+
+// This was a problem in Sema, but only shows up as noinline missing
+// in CodeGen.
+
+// CHECK: define linkonce_odr void @_ZN6VectorIiE13growStorageByEv(%struct.Vector* %this) nounwind noinline
+
+template <class Ty> struct Vector {
+ void growStorageBy();
+};
+template <class T> __attribute__((noinline)) void Vector<T>::growStorageBy() {
+}
+void foo() {
+ Vector<int> strs;
+ strs.growStorageBy();
+}
diff --git a/test/CodeGenCXX/nrvo.cpp b/test/CodeGenCXX/nrvo.cpp
index 82caff880f5c..0efb35538038 100644
--- a/test/CodeGenCXX/nrvo.cpp
+++ b/test/CodeGenCXX/nrvo.cpp
@@ -13,10 +13,10 @@ public:
// CHECK-EH: define void @_Z5test0v
X test0() {
X x;
- // CHECK: call void @_ZN1XC1Ev
+ // CHECK: call {{.*}} @_ZN1XC1Ev
// CHECK-NEXT: ret void
- // CHECK-EH: call void @_ZN1XC1Ev
+ // CHECK-EH: call {{.*}} @_ZN1XC1Ev
// CHECK-EH-NEXT: ret void
return x;
}
@@ -24,13 +24,13 @@ X test0() {
// CHECK: define void @_Z5test1b(
// CHECK-EH: define void @_Z5test1b(
X test1(bool B) {
- // CHECK: tail call void @_ZN1XC1Ev
+ // CHECK: tail call {{.*}} @_ZN1XC1Ev
// CHECK-NEXT: ret void
X x;
if (B)
return (x);
return x;
- // CHECK-EH: tail call void @_ZN1XC1Ev
+ // CHECK-EH: tail call {{.*}} @_ZN1XC1Ev
// CHECK-EH-NEXT: ret void
}
@@ -45,18 +45,18 @@ X test2(bool B) {
return y;
return x;
- // CHECK: call void @_ZN1XC1Ev
- // CHECK-NEXT: call void @_ZN1XC1Ev
- // CHECK: call void @_ZN1XC1ERKS_
- // CHECK: call void @_ZN1XC1ERKS_
- // CHECK: call void @_ZN1XD1Ev
- // CHECK: call void @_ZN1XD1Ev
+ // CHECK: call {{.*}} @_ZN1XC1Ev
+ // CHECK-NEXT: call {{.*}} @_ZN1XC1Ev
+ // CHECK: call {{.*}} @_ZN1XC1ERKS_
+ // CHECK: call {{.*}} @_ZN1XC1ERKS_
+ // CHECK: call {{.*}} @_ZN1XD1Ev
+ // CHECK: call {{.*}} @_ZN1XD1Ev
// CHECK: ret void
// The block ordering in the -fexceptions IR is unfortunate.
- // CHECK-EH: call void @_ZN1XC1Ev
- // CHECK-EH-NEXT: invoke void @_ZN1XC1Ev
+ // CHECK-EH: call {{.*}} @_ZN1XC1Ev
+ // CHECK-EH-NEXT: invoke {{.*}} @_ZN1XC1Ev
// -> %invoke.cont, %lpad
// %invoke.cont:
@@ -64,7 +64,7 @@ X test2(bool B) {
// -> %if.then, %if.end
// %if.then: returning 'x'
- // CHECK-EH: invoke void @_ZN1XC1ERKS_
+ // CHECK-EH: invoke {{.*}} @_ZN1XC1ERKS_
// -> %cleanup, %lpad1
// %lpad: landing pad for ctor of 'y', dtor of 'y'
@@ -74,23 +74,23 @@ X test2(bool B) {
// -> %eh.cleanup
// %lpad1: landing pad for return copy ctors, EH cleanup for 'y'
- // CHECK-EH: invoke void @_ZN1XD1Ev
+ // CHECK-EH: invoke {{.*}} @_ZN1XD1Ev
// -> %eh.cleanup, %terminate.lpad
// %if.end: returning 'y'
- // CHECK-EH: invoke void @_ZN1XC1ERKS_
+ // CHECK-EH: invoke {{.*}} @_ZN1XC1ERKS_
// -> %cleanup, %lpad1
// %cleanup: normal cleanup for 'y'
- // CHECK-EH: invoke void @_ZN1XD1Ev
+ // CHECK-EH: invoke {{.*}} @_ZN1XD1Ev
// -> %invoke.cont11, %lpad
// %invoke.cont11: normal cleanup for 'x'
- // CHECK-EH: call void @_ZN1XD1Ev
+ // CHECK-EH: call {{.*}} @_ZN1XD1Ev
// CHECK-EH-NEXT: ret void
// %eh.cleanup: EH cleanup for 'x'
- // CHECK-EH: invoke void @_ZN1XD1Ev
+ // CHECK-EH: invoke {{.*}} @_ZN1XD1Ev
// -> %invoke.cont17, %terminate.lpad
// %invoke.cont17: rethrow block for %eh.cleanup.
@@ -121,13 +121,13 @@ extern "C" void exit(int) throw();
// CHECK: define void @_Z5test4b
X test4(bool B) {
{
- // CHECK: tail call void @_ZN1XC1Ev
+ // CHECK: tail call {{.*}} @_ZN1XC1Ev
X x;
// CHECK: br i1
if (B)
return x;
}
- // CHECK: tail call void @_ZN1XD1Ev
+ // CHECK: tail call {{.*}} @_ZN1XD1Ev
// CHECK: tail call void @exit(i32 1)
exit(1);
}
@@ -139,7 +139,7 @@ X test5() {
try {
may_throw();
} catch (X x) {
- // CHECK-EH: invoke void @_ZN1XC1ERKS_
+ // CHECK-EH: invoke {{.*}} @_ZN1XC1ERKS_
// CHECK-EH: call void @__cxa_end_catch()
// CHECK-EH: ret void
return x;
diff --git a/test/CodeGenCXX/partial-destruction.cpp b/test/CodeGenCXX/partial-destruction.cpp
new file mode 100644
index 000000000000..82deca06cf80
--- /dev/null
+++ b/test/CodeGenCXX/partial-destruction.cpp
@@ -0,0 +1,169 @@
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - -fcxx-exceptions -fexceptions | FileCheck %s
+
+// Test IR generation for partial destruction of aggregates.
+
+void opaque();
+
+// Initializer lists.
+namespace test0 {
+ struct A { A(int); A(); ~A(); void *v; };
+ void test() {
+ A as[10] = { 5, 7 };
+ opaque();
+ }
+ // CHECK: define void @_ZN5test04testEv()
+ // CHECK: [[AS:%.*]] = alloca [10 x [[A:%.*]]], align
+ // CHECK-NEXT: [[ENDVAR:%.*]] = alloca [[A]]*
+ // CHECK-NEXT: [[EXN:%.*]] = alloca i8*
+ // CHECK-NEXT: [[SEL:%.*]] = alloca i32
+ // CHECK-NEXT: [[CLEANUP:%.*]] = alloca i32
+
+ // Initialize.
+ // CHECK-NEXT: [[E_BEGIN:%.*]] = getelementptr inbounds [10 x [[A]]]* [[AS]], i64 0, i64 0
+ // CHECK-NEXT: store [[A]]* [[E_BEGIN]], [[A]]** [[ENDVAR]]
+ // CHECK-NEXT: invoke void @_ZN5test01AC1Ei([[A]]* [[E_BEGIN]], i32 5)
+ // CHECK: [[E1:%.*]] = getelementptr inbounds [[A]]* [[E_BEGIN]], i64 1
+ // CHECK-NEXT: store [[A]]* [[E1]], [[A]]** [[ENDVAR]]
+ // CHECK-NEXT: invoke void @_ZN5test01AC1Ei([[A]]* [[E1]], i32 7)
+ // CHECK: [[E2:%.*]] = getelementptr inbounds [[A]]* [[E1]], i64 1
+ // CHECK-NEXT: store [[A]]* [[E2]], [[A]]** [[ENDVAR]]
+ // CHECK-NEXT: [[E_END:%.*]] = getelementptr inbounds [[A]]* [[E_BEGIN]], i64 10
+ // CHECK-NEXT: br label
+ // CHECK: [[E_CUR:%.*]] = phi [[A]]* [ [[E2]], {{%.*}} ], [ [[E_NEXT:%.*]], {{%.*}} ]
+ // CHECK-NEXT: invoke void @_ZN5test01AC1Ev([[A]]* [[E_CUR]])
+ // CHECK: [[E_NEXT]] = getelementptr inbounds [[A]]* [[E_CUR]], i64 1
+ // CHECK-NEXT: store [[A]]* [[E_NEXT]], [[A]]** [[ENDVAR]]
+ // CHECK-NEXT: [[T0:%.*]] = icmp eq [[A]]* [[E_NEXT]], [[E_END]]
+ // CHECK-NEXT: br i1 [[T0]],
+
+ // Run.
+ // CHECK: invoke void @_Z6opaquev()
+
+ // Normal destroy.
+ // CHECK: [[ED_BEGIN:%.*]] = getelementptr inbounds [10 x [[A]]]* [[AS]], i32 0, i32 0
+ // CHECK-NEXT: [[ED_END:%.*]] = getelementptr inbounds [[A]]* [[ED_BEGIN]], i64 10
+ // CHECK-NEXT: br label
+ // CHECK: [[ED_AFTER:%.*]] = phi [[A]]* [ [[ED_END]], {{%.*}} ], [ [[ED_CUR:%.*]], {{%.*}} ]
+ // CHECK-NEXT: [[ED_CUR]] = getelementptr inbounds [[A]]* [[ED_AFTER]], i64 -1
+ // CHECK-NEXT: invoke void @_ZN5test01AD1Ev([[A]]* [[ED_CUR]])
+ // CHECK: [[T0:%.*]] = icmp eq [[A]]* [[ED_CUR]], [[ED_BEGIN]]
+ // CHECK-NEXT: br i1 [[T0]],
+ // CHECK: ret void
+
+ // Partial destroy for initialization.
+ // CHECK: llvm.eh.selector({{.*}}, i32 0)
+ // CHECK: [[PARTIAL_END:%.*]] = load [[A]]** [[ENDVAR]]
+ // CHECK-NEXT: [[T0:%.*]] = icmp eq [[A]]* [[E_BEGIN]], [[PARTIAL_END]]
+ // CHECK-NEXT: br i1 [[T0]],
+ // CHECK: [[E_AFTER:%.*]] = phi [[A]]* [ [[PARTIAL_END]], {{%.*}} ], [ [[E_CUR:%.*]], {{%.*}} ]
+ // CHECK-NEXT: [[E_CUR]] = getelementptr inbounds [[A]]* [[E_AFTER]], i64 -1
+ // CHECK-NEXT: invoke void @_ZN5test01AD1Ev([[A]]* [[E_CUR]])
+ // CHECK: [[T0:%.*]] = icmp eq [[A]]* [[E_CUR]], [[E_BEGIN]]
+ // CHECK-NEXT: br i1 [[T0]],
+
+ // Primary EH destructor.
+ // CHECK: llvm.eh.selector({{.*}}, i32 0)
+ // CHECK: [[E0:%.*]] = getelementptr inbounds [10 x [[A]]]* [[AS]], i32 0, i32 0
+ // CHECK-NEXT: [[E_END:%.*]] = getelementptr inbounds [[A]]* [[E0]], i64 10
+ // CHECK-NEXT: br label
+
+ // Partial destructor for primary normal destructor.
+ // FIXME: There's some really bad block ordering here which causes
+ // the partial destroy for the primary normal destructor to fall
+ // within the primary EH destructor.
+ // CHECK: llvm.eh.selector({{.*}}, i32 0)
+ // CHECK: [[T0:%.*]] = icmp eq [[A]]* [[ED_BEGIN]], [[ED_CUR]]
+ // CHECK-NEXT: br i1 [[T0]]
+ // CHECK: [[EDD_AFTER:%.*]] = phi [[A]]* [ [[ED_CUR]], {{%.*}} ], [ [[EDD_CUR:%.*]], {{%.*}} ]
+ // CHECK-NEXT: [[EDD_CUR]] = getelementptr inbounds [[A]]* [[EDD_AFTER]], i64 -1
+ // CHECK-NEXT: invoke void @_ZN5test01AD1Ev([[A]]* [[EDD_CUR]])
+ // CHECK: [[T0:%.*]] = icmp eq [[A]]* [[EDD_CUR]], [[ED_BEGIN]]
+ // CHECK-NEXT: br i1 [[T0]]
+
+ // Back to the primary EH destructor.
+ // CHECK: [[E_AFTER:%.*]] = phi [[A]]* [ [[E_END]], {{%.*}} ], [ [[E_CUR:%.*]], {{%.*}} ]
+ // CHECK-NEXT: [[E_CUR]] = getelementptr inbounds [[A]]* [[E_AFTER]], i64 -1
+ // CHECK-NEXT: invoke void @_ZN5test01AD1Ev([[A]]* [[E_CUR]])
+ // CHECK: [[T0:%.*]] = icmp eq [[A]]* [[E_CUR]], [[E0]]
+ // CHECK-NEXT: br i1 [[T0]],
+
+}
+
+namespace test1 {
+ struct A { A(); A(int); ~A(); };
+ struct B { A x, y, z; int w; };
+
+ void test() {
+ B v = { 5, 6, 7, 8 };
+ }
+ // CHECK: define void @_ZN5test14testEv()
+ // CHECK: [[V:%.*]] = alloca [[B:%.*]], align 4
+ // CHECK-NEXT: alloca i8*
+ // CHECK-NEXT: alloca i32
+ // CHECK-NEXT: alloca i32
+ // CHECK-NEXT: [[X:%.*]] = getelementptr inbounds [[B]]* [[V]], i32 0, i32 0
+ // CHECK-NEXT: call void @_ZN5test11AC1Ei([[A:%.*]]* [[X]], i32 5)
+ // CHECK-NEXT: [[Y:%.*]] = getelementptr inbounds [[B]]* [[V]], i32 0, i32 1
+ // CHECK-NEXT: invoke void @_ZN5test11AC1Ei([[A]]* [[Y]], i32 6)
+ // CHECK: [[Z:%.*]] = getelementptr inbounds [[B]]* [[V]], i32 0, i32 2
+ // CHECK-NEXT: invoke void @_ZN5test11AC1Ei([[A]]* [[Z]], i32 7)
+ // CHECK: [[W:%.*]] = getelementptr inbounds [[B]]* [[V]], i32 0, i32 3
+ // CHECK-NEXT: store i32 8, i32* [[W]], align 4
+ // CHECK-NEXT: call void @_ZN5test11BD1Ev([[B]]* [[V]])
+ // CHECK-NEXT: ret void
+
+ // FIXME: again, the block ordering is pretty bad here
+ // CHECK: eh.selector({{.*}}, i32 0)
+ // CHECK: eh.selector({{.*}}, i32 0)
+ // CHECK: invoke void @_ZN5test11AD1Ev([[A]]* [[Y]])
+ // CHECK: invoke void @_ZN5test11AD1Ev([[A]]* [[X]])
+}
+
+namespace test2 {
+ struct A { A(); ~A(); };
+
+ void test() {
+ A v[4][7];
+
+ // CHECK: define void @_ZN5test24testEv()
+ // CHECK: [[V:%.*]] = alloca [4 x [7 x [[A:%.*]]]], align 1
+ // CHECK-NEXT: alloca i8*
+ // CHECK-NEXT: alloca i32
+ // CHECK-NEXT: alloca i32
+
+ // Main initialization loop.
+ // CHECK-NEXT: [[BEGIN:%.*]] = getelementptr inbounds [4 x [7 x [[A]]]]* [[V]], i32 0, i32 0, i32 0
+ // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [[A]]* [[BEGIN]], i64 28
+ // CHECK-NEXT: br label
+ // CHECK: [[CUR:%.*]] = phi [[A]]* [ [[BEGIN]], {{%.*}} ], [ [[NEXT:%.*]], {{%.*}} ]
+ // CHECK-NEXT: invoke void @_ZN5test21AC1Ev([[A]]* [[CUR]])
+ // CHECK: [[NEXT:%.*]] = getelementptr inbounds [[A]]* [[CUR]], i64 1
+ // CHECK-NEXT: [[DONE:%.*]] = icmp eq [[A]]* [[NEXT]], [[END]]
+ // CHECK-NEXT: br i1 [[DONE]],
+
+ // Partial destruction landing pad.
+ // CHECK: llvm.eh.exception()
+ // CHECK: [[EMPTY:%.*]] = icmp eq [[A]]* [[BEGIN]], [[CUR]]
+ // CHECK-NEXT: br i1 [[EMPTY]],
+ // CHECK: [[PAST:%.*]] = phi [[A]]* [ [[CUR]], {{%.*}} ], [ [[DEL:%.*]], {{%.*}} ]
+ // CHECK-NEXT: [[DEL]] = getelementptr inbounds [[A]]* [[PAST]], i64 -1
+ // CHECK-NEXT: invoke void @_ZN5test21AD1Ev([[A]]* [[DEL]])
+ // CHECK: [[T0:%.*]] = icmp eq [[A]]* [[DEL]], [[BEGIN]]
+ // CHECK-NEXT: br i1 [[T0]],
+ }
+
+}
+
+// PR10351
+namespace test3 {
+ struct A { A(); ~A(); void *p; };
+ struct B {
+ B() {}
+ A a;
+ };
+
+ B *test() {
+ return new B[10];
+ // invoke void @_ZN5test31BD1Ev(
+ }
+}
diff --git a/test/CodeGenCXX/pointers-to-data-members.cpp b/test/CodeGenCXX/pointers-to-data-members.cpp
index 2a22d23e509d..f0246c89b699 100644
--- a/test/CodeGenCXX/pointers-to-data-members.cpp
+++ b/test/CodeGenCXX/pointers-to-data-members.cpp
@@ -35,7 +35,7 @@ namespace ZeroInit {
} ssa[2];
void test_ssa() { (void) ssa; }
- // CHECK-GLOBAL: @_ZN8ZeroInit2ssE = internal global %1 { %struct.anon { i64 -1 } }
+ // CHECK-GLOBAL: @_ZN8ZeroInit2ssE = internal global %struct.anon.1 { %struct.anon.2 { i64 -1 } }
struct {
struct {
int A::*pa;
@@ -55,7 +55,7 @@ namespace ZeroInit {
};
struct C : A, B { int j; };
- // CHECK-GLOBAL: @_ZN8ZeroInit1cE = global {{%.*}} { %"struct.PR7139::ptr_to_member_struct" { i64 -1, i32 0 }, %"struct.ZeroInit::B" { [10 x %"struct.PR7139::ptr_to_member_struct"] [%"struct.PR7139::ptr_to_member_struct" { i64 -1, i32 0 }, %"struct.PR7139::ptr_to_member_struct" { i64 -1, i32 0 }, %"struct.PR7139::ptr_to_member_struct" { i64 -1, i32 0 }, %"struct.PR7139::ptr_to_member_struct" { i64 -1, i32 0 }, %"struct.PR7139::ptr_to_member_struct" { i64 -1, i32 0 }, %"struct.PR7139::ptr_to_member_struct" { i64 -1, i32 0 }, %"struct.PR7139::ptr_to_member_struct" { i64 -1, i32 0 }, %"struct.PR7139::ptr_to_member_struct" { i64 -1, i32 0 }, %"struct.PR7139::ptr_to_member_struct" { i64 -1, i32 0 }, %"struct.PR7139::ptr_to_member_struct" { i64 -1, i32 0 }], i8 0, i64 -1 }, i32 0 }, align 8
+ // CHECK-GLOBAL: @_ZN8ZeroInit1cE = global {{%.*}} { %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::B" { [10 x %"struct.ZeroInit::A"] [%"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }], i8 0, i64 -1 }, i32 0 }, align 8
C c;
}
@@ -227,6 +227,6 @@ namespace test4 {
struct C : virtual B { int *C_p; };
struct D : C { int *D_p; };
- // CHECK-GLOBAL: @_ZN5test41dE = global %"struct.test4::D" { %"struct.test4::C.base" zeroinitializer, i32* null, %"struct.VirtualBases::C.base" { i32 (...)** null, i64 -1 }, %"struct.test4::A" zeroinitializer }, align 8
+ // CHECK-GLOBAL: @_ZN5test41dE = global %"struct.test4::D" { %"struct.test4::C.base" zeroinitializer, i32* null, %"struct.test4::B.base" { i32 (...)** null, i64 -1 }, %"struct.test4::A" zeroinitializer }, align 8
D d;
}
diff --git a/test/CodeGenCXX/pr9965.cpp b/test/CodeGenCXX/pr9965.cpp
index b87fcf42023b..596dee9caaa3 100644
--- a/test/CodeGenCXX/pr9965.cpp
+++ b/test/CodeGenCXX/pr9965.cpp
@@ -7,6 +7,6 @@ struct X
X<int> x;
// CHECK: define internal void @__cxx_global_var_init()
-// CHECK: call void @_ZN1XIiEC1Ev
-// CHECK: define linkonce_odr void @_ZN1XIiEC1Ev
-// CHECK: define linkonce_odr void @_ZN1XIiEC2Ev
+// CHECK: call {{.*}} @_ZN1XIiEC1Ev
+// CHECK: define linkonce_odr {{.*}} @_ZN1XIiEC1Ev
+// CHECK: define linkonce_odr {{.*}} @_ZN1XIiEC2Ev
diff --git a/test/CodeGenCXX/references.cpp b/test/CodeGenCXX/references.cpp
index 25bc8d801790..4bbc251ab5d0 100644
--- a/test/CodeGenCXX/references.cpp
+++ b/test/CodeGenCXX/references.cpp
@@ -235,7 +235,7 @@ struct A {
};
// CHECK: define internal void @__cxx_global_var_init
-// CHECK: call void @_ZN2N31AC1Ei(%"class.N2::X"* @_ZGRN2N35sA123E, i32 123)
+// CHECK: call void @_ZN2N31AC1Ei(%"struct.N3::A"* @_ZGRN2N35sA123E, i32 123)
// CHECK: call i32 @__cxa_atexit
// CHECK: ret void
const A &sA123 = A(123);
@@ -250,7 +250,7 @@ struct A {
void f() {
// CHECK: define void @_ZN2N41fEv
- // CHECK: call void @_ZN2N41AC1Ev(%"class.N2::X"* @_ZGRZN2N41fEvE2ar)
+ // CHECK: call void @_ZN2N41AC1Ev(%"struct.N4::A"* @_ZGRZN2N41fEvE2ar)
// CHECK: call i32 @__cxa_atexit
// CHECK: ret void
static const A& ar = A();
@@ -269,3 +269,31 @@ void h() {
f(g().b);
}
}
+
+// PR9565
+namespace PR9565 {
+ struct a { int a : 10, b : 10; };
+ // CHECK: define void @_ZN6PR95651fEv()
+ void f() {
+ // CHECK: call void @llvm.memcpy
+ a x = { 0, 0 };
+ // CHECK: [[WITH_SEVENTEEN:%[a-zA-Z0-9]+]] = or i32 [[WITHOUT_SEVENTEEN:%[a-zA-Z0-9]+]], 17
+ // CHECK: store i32 [[WITH_SEVENTEEN]], i32* [[XA:%[a-zA-Z0-9]+]]
+ x.a = 17;
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: load
+ // CHECK-NEXT: and
+ // CHECK-NEXT: shl
+ // CHECK-NEXT: ashr
+ // CHECK-NEXT: store i32
+ // CHECK-NEXT: store i32*
+ const int &y = x.a;
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: load
+ // CHECK-NEXT: and
+ // CHECK-NEXT: or
+ // CHECK-NEXT: store i32
+ x.b = 19;
+ // CHECK-NEXT: ret void
+ }
+}
diff --git a/test/CodeGenCXX/static-init-3.cpp b/test/CodeGenCXX/static-init-3.cpp
index bd717caaa172..dc28d5a32a63 100644
--- a/test/CodeGenCXX/static-init-3.cpp
+++ b/test/CodeGenCXX/static-init-3.cpp
@@ -16,8 +16,8 @@ struct X1
}
};
-// CHECK: @_ZN2X1I2X2I1BEE8instanceE = weak_odr global %struct.X0* null, align 8
-// CHECJ: @_ZN2X1I2X2I1AEE8instanceE = weak_odr global %struct.X0* null, align 8
+// CHECK: @_ZN2X1I2X2I1BEE8instanceE = weak_odr global %struct.X2* null, align 8
+// CHECJ: @_ZN2X1I2X2I1AEE8instanceE = weak_odr global %struct.X2* null, align 8
template<class T> T & X1<T>::instance = X1<T>::get();
class A { };
diff --git a/test/CodeGenCXX/static-init.cpp b/test/CodeGenCXX/static-init.cpp
index 78749a7a2faf..d488e636696e 100644
--- a/test/CodeGenCXX/static-init.cpp
+++ b/test/CodeGenCXX/static-init.cpp
@@ -16,6 +16,9 @@ void f() {
// CHECK: call void @_ZN1AC1Ev
// CHECK: call i32 @__cxa_atexit(void (i8*)* bitcast (void (%struct.A*)* @_ZN1AD1Ev to void (i8*)*), i8* getelementptr inbounds (%struct.A* @_ZZ1fvE1a, i32 0, i32 0), i8* bitcast (i8** @__dso_handle to i8*))
// CHECK: call void @__cxa_guard_release
+
+ // rdar://problem/9496726
+ // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 false, i1 false, i1 false)
static A a;
}
diff --git a/test/CodeGenCXX/stmtexpr.cpp b/test/CodeGenCXX/stmtexpr.cpp
index 0828d592fec1..1f0e4ac4bf29 100644
--- a/test/CodeGenCXX/stmtexpr.cpp
+++ b/test/CodeGenCXX/stmtexpr.cpp
@@ -46,11 +46,11 @@ void foo3()
void foo4()
{
-// CHECK: call void @_ZN1AC1Ei
-// CHECK: call void @_ZN1AC1ERKS_
-// CHECK: call void @_ZN1AD1Ev
-// CHECK: call void @_ZN1BC1ERK1A
-// CHECK: call void @_ZN1AD1Ev
+// CHECK: call {{.*}} @_ZN1AC1Ei
+// CHECK: call {{.*}} @_ZN1AC1ERKS_
+// CHECK: call {{.*}} @_ZN1AD1Ev
+// CHECK: call {{.*}} @_ZN1BC1ERK1A
+// CHECK: call {{.*}} @_ZN1AD1Ev
const B &b = ({ A a(1); a; });
if (b.i != 1)
abort();
diff --git a/test/CodeGenCXX/template-anonymous-types.cpp b/test/CodeGenCXX/template-anonymous-types.cpp
index 68bdc0c4a47d..72fe090ceb7f 100644
--- a/test/CodeGenCXX/template-anonymous-types.cpp
+++ b/test/CodeGenCXX/template-anonymous-types.cpp
@@ -32,6 +32,6 @@ void test() {
// CHECK: define internal void @"_ZN1XIN1S3$_1EEC2ES1_"(%struct.X* %this, i32 %t) unnamed_addr
//
// FOO's instantiation of X:
- // CHECK: define internal i32 @"_ZN1XIN1S3$_0EE1fEv"(%struct.X* %this)
- // CHECK: define internal void @"_ZN1XIN1S3$_0EEC2ES1_"(%struct.X* %this, i32 %t) unnamed_addr
+ // CHECK: define internal i32 @"_ZN1XIN1S3$_0EE1fEv"(%struct.X.0* %this)
+ // CHECK: define internal void @"_ZN1XIN1S3$_0EEC2ES1_"(%struct.X.0* %this, i32 %t) unnamed_addr
}
diff --git a/test/CodeGenCXX/temporaries.cpp b/test/CodeGenCXX/temporaries.cpp
index 348d51e019a6..8aeca653da55 100644
--- a/test/CodeGenCXX/temporaries.cpp
+++ b/test/CodeGenCXX/temporaries.cpp
@@ -421,28 +421,24 @@ namespace Elision {
void test4() {
// CHECK: [[X:%.*]] = alloca [[A]], align 8
// CHECK-NEXT: [[XS:%.*]] = alloca [2 x [[A]]], align 16
- // CHECK-NEXT: [[I:%.*]] = alloca i64
// CHECK-NEXT: call void @_ZN7Elision1AC1Ev([[A]]* [[X]])
A x;
- // CHECK-NEXT: [[XS0:%.*]] = getelementptr inbounds [2 x [[A]]]* [[XS]], i32 0, i32 0
+ // CHECK-NEXT: [[XS0:%.*]] = getelementptr inbounds [2 x [[A]]]* [[XS]], i64 0, i64 0
// CHECK-NEXT: call void @_ZN7Elision1AC1Ev([[A]]* [[XS0]])
- // CHECK-NEXT: [[XS1:%.*]] = getelementptr inbounds [2 x [[A]]]* [[XS]], i32 0, i32 1
+ // CHECK-NEXT: [[XS1:%.*]] = getelementptr inbounds [[A]]* [[XS0]], i64 1
// CHECK-NEXT: call void @_ZN7Elision1AC1ERKS0_([[A]]* [[XS1]], [[A]]* [[X]])
- // CHECK-NEXT: [[XSB:%.*]] = bitcast [2 x [[A]]]* [[XS]] to [[A]]*
A xs[] = { A(), x };
- // CHECK-NEXT: store i64 2, i64* [[I]]
- // CHECK-NEXT: br label
- // CHECK: [[I0:%.*]] = load i64* [[I]]
- // CHECK-NEXT: icmp ne i64 [[I0]], 0
- // CHECK-NEXT: br i1
- // CHECK: [[I1:%.*]] = load i64* [[I]]
- // CHECK-NEXT: [[I2:%.*]] = sub i64 [[I1]], 1
- // CHECK-NEXT: [[XSI:%.*]] = getelementptr inbounds [[A]]* [[XSB]], i64 [[I2]]
- // CHECK-NEXT: call void @_ZN7Elision1AD1Ev([[A]]* [[XSI]])
+ // CHECK-NEXT: [[BEGIN:%.*]] = getelementptr inbounds [2 x [[A]]]* [[XS]], i32 0, i32 0
+ // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [[A]]* [[BEGIN]], i64 2
// CHECK-NEXT: br label
+ // CHECK: [[AFTER:%.*]] = phi [[A]]*
+ // CHECK-NEXT: [[CUR:%.*]] = getelementptr inbounds [[A]]* [[AFTER]], i64 -1
+ // CHECK-NEXT: call void @_ZN7Elision1AD1Ev([[A]]* [[CUR]])
+ // CHECK-NEXT: [[T0:%.*]] = icmp eq [[A]]* [[CUR]], [[BEGIN]]
+ // CHECK-NEXT: br i1 [[T0]],
// CHECK: call void @_ZN7Elision1AD1Ev([[A]]* [[X]])
}
diff --git a/test/CodeGenCXX/value-init.cpp b/test/CodeGenCXX/value-init.cpp
index a5a0b67d57d8..04a18b3fa801 100644
--- a/test/CodeGenCXX/value-init.cpp
+++ b/test/CodeGenCXX/value-init.cpp
@@ -105,34 +105,24 @@ void f() {
// CHECK: call void @_ZN6PR98014TestC1Ei
// CHECK-NOT: call void @llvm.memset.p0i8.i64
// CHECK: call void @_ZN6PR98014TestC1Ev
- // CHECK-NOT: call void @llvm.memset.p0i8.i64
- // CHECK: call void @_ZN6PR98014TestC1Ev
Test partial[3] = { 1 };
// CHECK-NOT: call void @llvm.memset.p0i8.i64
// CHECK: call void @_ZN6PR98014TestC1Ev
- // CHECK-NOT: call void @llvm.memset.p0i8.i64
- // CHECK: call void @_ZN6PR98014TestC1Ev
- // CHECK-NOT: call void @llvm.memset.p0i8.i64
- // CHECK: call void @_ZN6PR98014TestC1Ev
+ // CHECK-NOT: call void @_ZN6PR98014TestC1Ev
Test empty[3] = {};
// CHECK: call void @llvm.memset.p0i8.i64
// CHECK-NOT: call void @llvm.memset.p0i8.i64
// CHECK: call void @_ZN6PR98015Test2C1Ev
- // CHECK-NOT: call void @llvm.memset.p0i8.i64
- // CHECK: call void @_ZN6PR98015Test2C1Ev
- // CHECK-NOT: call void @llvm.memset.p0i8.i64
- // CHECK: call void @_ZN6PR98015Test2C1Ev
+ // CHECK-NOT: call void @_ZN6PR98015Test2C1Ev
Test2 empty2[3] = {};
// CHECK: call void @llvm.memset.p0i8.i64
// CHECK-NOT: call void @llvm.memset.p0i8.i64
// CHECK: call void @_ZN6PR98015Test3C1Ev
// CHECK-NOT: call void @llvm.memset.p0i8.i64
- // CHECK: call void @_ZN6PR98015Test3C1Ev
- // CHECK-NOT: call void @llvm.memset.p0i8.i64
- // CHECK: call void @_ZN6PR98015Test3C1Ev
+ // CHECK-NOT: call void @_ZN6PR98015Test3C1Ev
Test3 empty3[3] = {};
}
@@ -189,10 +179,7 @@ namespace zeroinit {
X3<int>().f();
}
- // CHECK: define linkonce_odr void @_ZN8zeroinit2X3IiEC2Ev(%"struct.zeroinit::X3"* %this) unnamed_addr
- // CHECK: call void @llvm.memset.p0i8.i64
- // CHECK-NEXT: call void @_ZN8zeroinit2X2IiEC2Ev
- // CHECK-NEXT: ret void
+ // More checks at EOF
}
namespace PR8726 {
@@ -207,3 +194,51 @@ void f(const C& c) {
}
}
+
+// rdar://problem/9355931
+namespace test6 {
+ struct A { A(); A(int); };
+
+ void test() {
+ A arr[10][20] = { 5 };
+ };
+ // CHECK: define void @_ZN5test64testEv()
+ // CHECK: [[ARR:%.*]] = alloca [10 x [20 x [[A:%.*]]]],
+
+ // CHECK-NEXT: [[INNER:%.*]] = getelementptr inbounds [10 x [20 x [[A]]]]* [[ARR]], i64 0, i64 0
+ // CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [20 x [[A]]]* [[INNER]], i64 0, i64 0
+ // CHECK-NEXT: call void @_ZN5test61AC1Ei([[A]]* [[T0]], i32 5)
+ // CHECK-NEXT: [[BEGIN:%.*]] = getelementptr inbounds [[A]]* [[T0]], i64 1
+ // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [[A]]* [[T0]], i64 20
+ // CHECK-NEXT: br label
+ // CHECK: [[CUR:%.*]] = phi [[A]]* [ [[BEGIN]], {{%.*}} ], [ [[NEXT:%.*]], {{%.*}} ]
+ // CHECK-NEXT: call void @_ZN5test61AC1Ev([[A]]* [[CUR]])
+ // CHECK-NEXT: [[NEXT]] = getelementptr inbounds [[A]]* [[CUR]], i64 1
+ // CHECK-NEXT: [[T0:%.*]] = icmp eq [[A]]* [[NEXT]], [[END]]
+ // CHECK-NEXT: br i1
+
+ // CHECK: [[BEGIN:%.*]] = getelementptr inbounds [20 x [[A]]]* [[INNER]], i64 1
+ // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [20 x [[A]]]* [[INNER]], i64 10
+ // CHECK-NEXT: br label
+ // CHECK: [[CUR:%.*]] = phi [20 x [[A]]]* [ [[BEGIN]], {{%.*}} ], [ [[NEXT:%.*]], {{%.*}} ]
+
+ // Inner loop.
+ // CHECK-NEXT: [[IBEGIN:%.*]] = getelementptr inbounds [20 x [[A]]]* [[CUR]], i32 0, i32 0
+ // CHECK-NEXT: [[IEND:%.*]] = getelementptr inbounds [[A]]* [[IBEGIN]], i64 20
+ // CHECK-NEXT: br label
+ // CHECK: [[ICUR:%.*]] = phi [[A]]* [ [[IBEGIN]], {{%.*}} ], [ [[INEXT:%.*]], {{%.*}} ]
+ // CHECK-NEXT: call void @_ZN5test61AC1Ev([[A]]* [[ICUR]])
+ // CHECK-NEXT: [[INEXT:%.*]] = getelementptr inbounds [[A]]* [[ICUR]], i64 1
+ // CHECK-NEXT: [[T0:%.*]] = icmp eq [[A]]* [[INEXT]], [[IEND]]
+ // CHECK-NEXT: br i1 [[T0]],
+
+ // CHECK: [[NEXT]] = getelementptr inbounds [20 x [[A]]]* [[CUR]], i64 1
+ // CHECK-NEXT: [[T0:%.*]] = icmp eq [20 x [[A]]]* [[NEXT]], [[END]]
+ // CHECK-NEXT: br i1 [[T0]]
+ // CHECK: ret void
+}
+
+// CHECK: define linkonce_odr void @_ZN8zeroinit2X3IiEC2Ev(%"struct.zeroinit::X3"* %this) unnamed_addr
+// CHECK: call void @llvm.memset.p0i8.i64
+// CHECK-NEXT: call void @_ZN8zeroinit2X2IiEC2Ev
+// CHECK-NEXT: ret void
diff --git a/test/CodeGenCXX/variadic-templates.cpp b/test/CodeGenCXX/variadic-templates.cpp
index 4f3cf1fe9db6..90c837067559 100644
--- a/test/CodeGenCXX/variadic-templates.cpp
+++ b/test/CodeGenCXX/variadic-templates.cpp
@@ -9,4 +9,15 @@ int get_num_types(Types...) {
// CHECK: ret i32 3
template int get_num_types(int, float, double);
+// PR10260 - argument packs that expand to nothing
+namespace test1 {
+ template <class... T> void foo() {
+ int values[sizeof...(T)+1] = { T::value... };
+ // CHECK: define linkonce_odr void @_ZN5test13fooIJEEEvv()
+ // CHECK: alloca [1 x i32], align 4
+ }
+ void test() {
+ foo<>();
+ }
+}
diff --git a/test/CodeGenCXX/virt-call-offsets.cpp b/test/CodeGenCXX/virt-call-offsets.cpp
index 3eb6b5da7d0c..5eef6fea9e6f 100644
--- a/test/CodeGenCXX/virt-call-offsets.cpp
+++ b/test/CodeGenCXX/virt-call-offsets.cpp
@@ -5,4 +5,4 @@ struct B : A {};
struct C : B { virtual void a(); };
void (C::*x)() = &C::a;
-// CHECK: @x = global %0 { i{{[0-9]+}} 1, i{{[0-9]+}} 0 }
+// CHECK: @x = global { i{{[0-9]+}}, i{{[0-9]+}} } { i{{[0-9]+}} 1, i{{[0-9]+}} 0 }
diff --git a/test/CodeGenCXX/virtual-base-destructor-call.cpp b/test/CodeGenCXX/virtual-base-destructor-call.cpp
index f028e4c733fe..2424d218d6b7 100644
--- a/test/CodeGenCXX/virtual-base-destructor-call.cpp
+++ b/test/CodeGenCXX/virtual-base-destructor-call.cpp
@@ -18,34 +18,34 @@ int main() {
// basic_iostream's complete dtor calls its base dtor, then its
// virtual base's dtor.
-// CHECK: define linkonce_odr void @_ZN14basic_iostreamIcED1Ev(%struct.basic_iostream* %this) unnamed_addr
-// CHECK: call void @_ZN14basic_iostreamIcED2Ev
-// CHECK: call void @_ZN9basic_iosD2Ev
+// CHECK: define linkonce_odr {{.*}} @_ZN14basic_iostreamIcED1Ev(%struct.basic_iostream* %this) unnamed_addr
+// CHECK: call {{.*}} @_ZN14basic_iostreamIcED2Ev
+// CHECK: call {{.*}} @_ZN9basic_iosD2Ev
// basic_iostream's base dtor calls its non-virtual base dtor.
-// CHECK: define linkonce_odr void @_ZN14basic_iostreamIcED2Ev(%struct.basic_iostream* %this, i8** %vtt) unnamed_addr
-// CHECK: call void @_ZN13basic_istreamIcED2Ev
+// CHECK: define linkonce_odr {{.*}} @_ZN14basic_iostreamIcED2Ev(%struct.basic_iostream* %this, i8** %vtt) unnamed_addr
+// CHECK: call {{.*}} @_ZN13basic_istreamIcED2Ev
// CHECK: }
// basic_iostream's deleting dtor calls its complete dtor, then
// operator delete().
-// CHECK: define linkonce_odr void @_ZN14basic_iostreamIcED0Ev(%struct.basic_iostream* %this) unnamed_addr
-// CHECK: call void @_ZN14basic_iostreamIcED1Ev
-// CHECK: call void @_ZdlPv
+// CHECK: define linkonce_odr {{.*}} @_ZN14basic_iostreamIcED0Ev(%struct.basic_iostream* %this) unnamed_addr
+// CHECK: call {{.*}} @_ZN14basic_iostreamIcED1Ev
+// CHECK: call {{.*}} @_ZdlPv
// basic_istream's complete dtor calls the base dtor,
// then its virtual base's base dtor.
-// CHECK: define linkonce_odr void @_ZN13basic_istreamIcED1Ev(%struct.basic_istream* %this) unnamed_addr
-// CHECK: call void @_ZN13basic_istreamIcED2Ev
-// CHECK: call void @_ZN9basic_iosD2Ev
+// CHECK: define linkonce_odr {{.*}} @_ZN13basic_istreamIcED1Ev(%struct.basic_istream* %this) unnamed_addr
+// CHECK: call {{.*}} @_ZN13basic_istreamIcED2Ev
+// CHECK: call {{.*}} @_ZN9basic_iosD2Ev
// basic_istream's deleting dtor calls the complete dtor, then
// operator delete().
-// CHECK: define linkonce_odr void @_ZN13basic_istreamIcED0Ev(%struct.basic_istream* %this) unnamed_addr
-// CHECK: call void @_ZN13basic_istreamIcED1Ev
-// CHECK: call void @_ZdlPv
+// CHECK: define linkonce_odr {{.*}} @_ZN13basic_istreamIcED0Ev(%struct.basic_istream* %this) unnamed_addr
+// CHECK: call {{.*}} @_ZN13basic_istreamIcED1Ev
+// CHECK: call {{.*}} @_ZdlPv
// basic_istream's base dtor is a no-op.
-// CHECK: define linkonce_odr void @_ZN13basic_istreamIcED2Ev(%struct.basic_istream* %this, i8** %vtt) unnamed_addr
+// CHECK: define linkonce_odr {{.*}} @_ZN13basic_istreamIcED2Ev(%struct.basic_istream* %this, i8** %vtt) unnamed_addr
// CHECK-NOT: call
// CHECK: }
diff --git a/test/CodeGenCXX/virtual-bases.cpp b/test/CodeGenCXX/virtual-bases.cpp
index cfb4c837162e..c9f13f853d1b 100644
--- a/test/CodeGenCXX/virtual-bases.cpp
+++ b/test/CodeGenCXX/virtual-bases.cpp
@@ -20,8 +20,8 @@ struct C : virtual A {
C(bool);
};
-// CHECK: define void @_ZN1CC1Eb(%struct.B* %this, i1 zeroext) unnamed_addr
-// CHECK: define void @_ZN1CC2Eb(%struct.B* %this, i8** %vtt, i1 zeroext) unnamed_addr
+// CHECK: define void @_ZN1CC1Eb(%struct.C* %this, i1 zeroext) unnamed_addr
+// CHECK: define void @_ZN1CC2Eb(%struct.C* %this, i8** %vtt, i1 zeroext) unnamed_addr
C::C(bool) { }
// PR6251
diff --git a/test/CodeGenCXX/virtual-functions-incomplete-types.cpp b/test/CodeGenCXX/virtual-functions-incomplete-types.cpp
index 052a0192d665..afa658f7d374 100644
--- a/test/CodeGenCXX/virtual-functions-incomplete-types.cpp
+++ b/test/CodeGenCXX/virtual-functions-incomplete-types.cpp
@@ -9,7 +9,7 @@ struct B {
void B::f() { }
-// CHECK: define i32 @_ZN1D1gEv(%struct.B* %this)
+// CHECK: define i32 @_ZN1D1gEv(%struct.D* %this)
// CHECK: declare void @_ZN1B1gEv()
struct C;
diff --git a/test/CodeGenCXX/virtual-pseudo-destructor-call.cpp b/test/CodeGenCXX/virtual-pseudo-destructor-call.cpp
index 285e3da75924..0d3574e46d33 100644
--- a/test/CodeGenCXX/virtual-pseudo-destructor-call.cpp
+++ b/test/CodeGenCXX/virtual-pseudo-destructor-call.cpp
@@ -5,6 +5,10 @@ struct A {
};
void f(A *a) {
- // CHECK: call void %
+ // CHECK: define {{.*}} @_Z1fP1A
+ // CHECK: load
+ // CHECK: load
+ // CHECK: [[CALLEE:%[a-zA-Z0-9.]*]] = load
+ // CHECK: call {{.*}} [[CALLEE]](
a->~A();
}
diff --git a/test/CodeGenCXX/visibility-inlines-hidden.cpp b/test/CodeGenCXX/visibility-inlines-hidden.cpp
index 760879a2a63c..f7fabed8c10a 100644
--- a/test/CodeGenCXX/visibility-inlines-hidden.cpp
+++ b/test/CodeGenCXX/visibility-inlines-hidden.cpp
@@ -77,7 +77,7 @@ namespace test1 {
a.foo();
}
// CHECK: declare void @_ZN5test11A3fooEv
-// CHECK: declare void @_ZN5test11AD1Ev
+// CHECK: declare {{.*}} @_ZN5test11AD1Ev
}
// PR8713
diff --git a/test/CodeGenCXX/visibility.cpp b/test/CodeGenCXX/visibility.cpp
index 7644e47ff780..fdccd4604545 100644
--- a/test/CodeGenCXX/visibility.cpp
+++ b/test/CodeGenCXX/visibility.cpp
@@ -422,3 +422,35 @@ namespace test21 {
// CHECK: define weak_odr void @_ZN6test211AILNS_2EnE0EE3fooEv(
template void A<en>::foo();
}
+
+// rdar://problem/9616154
+// Visibility on explicit specializations should take precedence.
+namespace test22 {
+ class A1 {};
+ class A2 {};
+
+ template <class T> struct B {};
+ template <> struct DEFAULT B<A1> {
+ static void foo();
+ static void bar() {}
+ };
+ template <> struct B<A2> {
+ static void foo();
+ static void bar() {}
+ };
+
+ void test() {
+ B<A1>::foo();
+ B<A1>::bar();
+ B<A2>::foo();
+ B<A2>::bar();
+ }
+ // CHECK: declare void @_ZN6test221BINS_2A1EE3fooEv()
+ // CHECK: define linkonce_odr void @_ZN6test221BINS_2A1EE3barEv()
+ // CHECK: declare void @_ZN6test221BINS_2A2EE3fooEv()
+ // CHECK: define linkonce_odr void @_ZN6test221BINS_2A2EE3barEv()
+ // CHECK-HIDDEN: declare void @_ZN6test221BINS_2A1EE3fooEv()
+ // CHECK-HIDDEN: define linkonce_odr void @_ZN6test221BINS_2A1EE3barEv()
+ // CHECK-HIDDEN: declare void @_ZN6test221BINS_2A2EE3fooEv()
+ // CHECK-HIDDEN: define linkonce_odr hidden void @_ZN6test221BINS_2A2EE3barEv()
+}
diff --git a/test/CodeGenCXX/vla.cpp b/test/CodeGenCXX/vla.cpp
new file mode 100644
index 000000000000..58cdf795ee5a
--- /dev/null
+++ b/test/CodeGenCXX/vla.cpp
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - | FileCheck %s
+
+// rdar://problem/9506377
+void test0(void *array, int n) {
+ // CHECK: define void @_Z5test0Pvi(
+ // CHECK: [[ARRAY:%.*]] = alloca i8*, align 8
+ // CHECK-NEXT: [[N:%.*]] = alloca i32, align 4
+ // CHECK-NEXT: [[REF:%.*]] = alloca i16*, align 8
+ // CHECK-NEXT: [[S:%.*]] = alloca i16, align 2
+ // CHECK-NEXT: store i8*
+ // CHECK-NEXT: store i32
+
+ // Capture the bounds.
+ // CHECK-NEXT: [[T0:%.*]] = load i32* [[N]], align 4
+ // CHECK-NEXT: [[DIM0:%.*]] = zext i32 [[T0]] to i64
+ // CHECK-NEXT: [[T0:%.*]] = load i32* [[N]], align 4
+ // CHECK-NEXT: [[T1:%.*]] = add nsw i32 [[T0]], 1
+ // CHECK-NEXT: [[DIM1:%.*]] = zext i32 [[T1]] to i64
+ typedef short array_t[n][n+1];
+
+ // CHECK-NEXT: [[T0:%.*]] = load i8** [[ARRAY]], align 8
+ // CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to i16*
+ // CHECK-NEXT: store i16* [[T1]], i16** [[REF]], align 8
+ array_t &ref = *(array_t*) array;
+
+ // CHECK-NEXT: [[T0:%.*]] = load i16** [[REF]]
+ // CHECK-NEXT: [[T1:%.*]] = mul nsw i64 1, [[DIM1]]
+ // CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds i16* [[T0]], i64 [[T1]]
+ // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds i16* [[T2]], i64 2
+ // CHECK-NEXT: store i16 3, i16* [[T3]]
+ ref[1][2] = 3;
+
+ // CHECK-NEXT: [[T0:%.*]] = load i16** [[REF]]
+ // CHECK-NEXT: [[T1:%.*]] = mul nsw i64 4, [[DIM1]]
+ // CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds i16* [[T0]], i64 [[T1]]
+ // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds i16* [[T2]], i64 5
+ // CHECK-NEXT: [[T4:%.*]] = load i16* [[T3]]
+ // CHECK-NEXT: store i16 [[T4]], i16* [[S]], align 2
+ short s = ref[4][5];
+
+ // CHECK-NEXT: ret void
+}
+
diff --git a/test/CodeGenCXX/volatile-1.cpp b/test/CodeGenCXX/volatile-1.cpp
index 3ae17bd41b75..1a69648d42a7 100644
--- a/test/CodeGenCXX/volatile-1.cpp
+++ b/test/CodeGenCXX/volatile-1.cpp
@@ -4,7 +4,7 @@
volatile int i, j, k;
volatile int ar[5];
volatile char c;
-// CHECK: @ci = global [[CINT:%.*]] zeroinitializer
+// CHECK: @ci = global [[CINT:.*]] zeroinitializer
volatile _Complex int ci;
volatile struct S {
#ifdef __cplusplus
diff --git a/test/CodeGenCXX/vtable-pointer-initialization.cpp b/test/CodeGenCXX/vtable-pointer-initialization.cpp
index f629c2db79ca..9b1eaa5ba775 100644
--- a/test/CodeGenCXX/vtable-pointer-initialization.cpp
+++ b/test/CodeGenCXX/vtable-pointer-initialization.cpp
@@ -41,16 +41,16 @@ struct B : Base {
void f() { B b; }
-// CHECK: define linkonce_odr void @_ZN1BC1Ev(%struct.A* %this) unnamed_addr
+// CHECK: define linkonce_odr void @_ZN1BC1Ev(%struct.B* %this) unnamed_addr
// CHECK: call void @_ZN1BC2Ev(
-// CHECK: define linkonce_odr void @_ZN1BD1Ev(%struct.A* %this) unnamed_addr
+// CHECK: define linkonce_odr void @_ZN1BD1Ev(%struct.B* %this) unnamed_addr
// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1B, i64 0, i64 2)
// CHECK: call void @_ZN5FieldD1Ev(
// CHECK: call void @_ZN4BaseD2Ev(
// CHECK: ret void
-// CHECK: define linkonce_odr void @_ZN1BC2Ev(%struct.A* %this) unnamed_addr
+// CHECK: define linkonce_odr void @_ZN1BC2Ev(%struct.B* %this) unnamed_addr
// CHECK: call void @_ZN4BaseC2Ev(
// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1B, i64 0, i64 2)
// CHECK: call void @_ZN5FieldC1Ev
diff --git a/test/CodeGenCXX/x86_32-arguments.cpp b/test/CodeGenCXX/x86_32-arguments.cpp
index 4c0603346f05..4d4339381dbe 100644
--- a/test/CodeGenCXX/x86_32-arguments.cpp
+++ b/test/CodeGenCXX/x86_32-arguments.cpp
@@ -89,7 +89,7 @@ struct s5 { s5(); int &x; };
s5 f5() { return s5(); }
// CHECK: define i32 @_Z4f6_0M2s6i(i32 %a)
-// CHECK: define i64 @_Z4f6_1M2s6FivE(%{{.*}} byval align 4)
+// CHECK: define i64 @_Z4f6_1M2s6FivE({ i32, i32 }* byval align 4)
// FIXME: It would be nice to avoid byval on the previous case.
struct s6 {};
typedef int s6::* s6_mdp;
diff --git a/test/CodeGenCXX/x86_64-arguments.cpp b/test/CodeGenCXX/x86_64-arguments.cpp
index 01f1a445b1c7..e1d9dfc1fc30 100644
--- a/test/CodeGenCXX/x86_64-arguments.cpp
+++ b/test/CodeGenCXX/x86_64-arguments.cpp
@@ -115,3 +115,37 @@ namespace test6 {
}
// CHECK: define i32 @_ZN5test64testENS_5outerE(i64 %x.coerce0, i32 %x.coerce1)
}
+
+namespace test7 {
+ struct StringRef {char* ptr; long len; };
+ class A { public: ~A(); };
+ A x(A, A, long, long, StringRef) { return A(); }
+ // Check that the StringRef is passed byval instead of expanded
+ // (which would split it between registers and memory).
+ // rdar://problem/9686430
+ // CHECK: define void @_ZN5test71xENS_1AES0_llNS_9StringRefE({{.*}} byval align 8)
+
+ // And a couple extra related tests:
+ A y(A, long double, long, long, StringRef) { return A(); }
+ // CHECK: define void @_ZN5test71yENS_1AEellNS_9StringRefE({{.*}} i8*
+ struct StringDouble {char * ptr; double d;};
+ A z(A, A, A, A, A, StringDouble) { return A(); }
+ A zz(A, A, A, A, StringDouble) { return A(); }
+ // CHECK: define void @_ZN5test71zENS_1AES0_S0_S0_S0_NS_12StringDoubleE({{.*}} byval align 8)
+ // CHECK: define void @_ZN5test72zzENS_1AES0_S0_S0_NS_12StringDoubleE({{.*}} i8*
+}
+
+namespace test8 {
+ // CHECK: declare void @_ZN5test83fooENS_1BE(%"class.test8::B"* byval align 8)
+ class A {
+ char big[17];
+ };
+
+ class B : public A {};
+
+ void foo(B b);
+ void bar() {
+ B b;
+ foo(b);
+ }
+}
diff --git a/test/CodeGenObjC/arc-arm.m b/test/CodeGenObjC/arc-arm.m
new file mode 100644
index 000000000000..a3d55c28f400
--- /dev/null
+++ b/test/CodeGenObjC/arc-arm.m
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -triple armv7-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -fblocks -fobjc-arc -o - %s | FileCheck %s
+
+id test0(void) {
+ extern id test0_helper(void);
+ // CHECK: [[T0:%.*]] = call arm_aapcscc i8* @test0_helper()
+ // CHECK-NEXT: ret i8* [[T0]]
+ return test0_helper();
+}
+
+void test1(void) {
+ extern id test1_helper(void);
+ // CHECK: [[T0:%.*]] = call arm_aapcscc i8* @test1_helper()
+ // CHECK-NEXT: call void asm sideeffect "mov\09r7, r7
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
+ // CHECK-NEXT: store i8* [[T1]],
+ // CHECK-NEXT: load
+ // CHECK-NEXT: call void @objc_release
+ // CHECK-NEXT: ret void
+ id x = test1_helper();
+}
diff --git a/test/CodeGenObjC/arc-block-ivar-layout.m b/test/CodeGenObjC/arc-block-ivar-layout.m
new file mode 100644
index 000000000000..50c35bacda06
--- /dev/null
+++ b/test/CodeGenObjC/arc-block-ivar-layout.m
@@ -0,0 +1,60 @@
+// RUN: %clang_cc1 -fblocks -fobjc-arc -fobjc-nonfragile-abi -fobjc-runtime-has-weak -triple x86_64-apple-darwin -O0 -emit-llvm %s -o %t-64.s
+// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
+// rdar://8991729
+
+__weak id wid;
+void x(id y) {}
+void y(int a) {}
+
+extern id opaque_id();
+
+void f() {
+ __block int byref_int = 0;
+ char ch = 'a';
+ char ch1 = 'b';
+ char ch2 = 'c';
+ short sh = 2;
+ const id bar = (id) opaque_id();
+ id baz = 0;
+ __strong id strong_void_sta;
+ __block id byref_bab = (id)0;
+ __block id bl_var1;
+ int i; double dob;
+
+// The patterns here are a sequence of bytes, each saying first how
+// many sizeof(void*) chunks to skip (high nibble) and then how many
+// to scan (low nibble). A zero byte says that we've reached the end
+// of the pattern.
+//
+// All of these patterns start with 01 3x because the block header on
+// LP64 consists of an isa pointer (which we're supposed to scan for
+// some reason) followed by three words (2 ints, a function pointer,
+// and a descriptor pointer).
+
+// Test 1
+// byref int, short, char, char, char, id, id, strong id, byref id
+// 01 35 10 00
+// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [4 x i8] c"\015\10\00"
+ void (^b)() = ^{
+ byref_int = sh + ch+ch1+ch2 ;
+ x(bar);
+ x(baz);
+ x((id)strong_void_sta);
+ x(byref_bab);
+ };
+ b();
+
+// Test 2
+// byref int, short, char, char, char, id, id, strong id, byref void*, byref id
+// 01 36 10 00
+// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [4 x i8] c"\016\10\00"
+ void (^c)() = ^{
+ byref_int = sh + ch+ch1+ch2 ;
+ x(bar);
+ x(baz);
+ x((id)strong_void_sta);
+ x(wid);
+ bl_var1 = 0;
+ x(byref_bab);
+ };
+}
diff --git a/test/CodeGenObjC/arc-bridged-cast.m b/test/CodeGenObjC/arc-bridged-cast.m
new file mode 100644
index 000000000000..3354bda5bf00
--- /dev/null
+++ b/test/CodeGenObjC/arc-bridged-cast.m
@@ -0,0 +1,90 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -fblocks -fobjc-arc -O2 -disable-llvm-optzns -o - %s | FileCheck %s
+
+typedef const void *CFTypeRef;
+typedef const struct __CFString *CFStringRef;
+
+@interface NSString
+@end
+
+CFTypeRef CFCreateSomething(void);
+CFStringRef CFCreateString(void);
+CFTypeRef CFGetSomething(void);
+CFStringRef CFGetString(void);
+
+id CreateSomething(void);
+NSString *CreateNSString(void);
+
+// CHECK: define void @bridge_transfer_from_cf
+void bridge_transfer_from_cf(int *i) {
+ // CHECK: store i32 7
+ *i = 7;
+ // CHECK: call i8* @CFCreateSomething()
+ id obj1 = (__bridge_transfer id)CFCreateSomething();
+ // CHECK-NOT: retain
+ // CHECK: store i32 11
+ *i = 11;
+ // CHECK: call i8* @CFCreateSomething()
+ // CHECK-NOT: retain
+ // CHECK: store i32 13
+ (void)(__bridge_transfer id)CFCreateSomething(), *i = 13;
+ // CHECK: call void @objc_release
+ // CHECK: store i32 17
+ *i = 17;
+ // CHECK: call void @objc_release
+ // CHECK-NEXT: ret void
+}
+
+// CHECK: define void @bridge_from_cf
+void bridge_from_cf(int *i) {
+ // CHECK: store i32 7
+ *i = 7;
+ // CHECK: call i8* @CFCreateSomething()
+ id obj1 = (__bridge id)CFCreateSomething();
+ // CHECK: objc_retainAutoreleasedReturnValue
+ // CHECK: store i32 11
+ *i = 11;
+ // CHECK: call i8* @CFCreateSomething()
+ // CHECK-NOT: release
+ // CHECK: store i32 13
+ (void)(__bridge id)CFCreateSomething(), *i = 13;
+ // CHECK: store i32 17
+ *i = 17;
+ // CHECK: call void @objc_release
+ // CHECK-NEXT: ret void
+}
+
+// CHECK: define void @bridge_retained_of_cf
+void bridge_retained_of_cf(int *i) {
+ *i = 7;
+ // CHECK: call i8* @CreateSomething()
+ CFTypeRef cf1 = (__bridge_retained CFTypeRef)CreateSomething();
+ // CHECK-NEXT: call i8* @objc_retainAutoreleasedReturnValue
+ // CHECK: store i32 11
+ *i = 11;
+ // CHECK: call i8* @CreateSomething()
+ (__bridge_retained CFTypeRef)CreateSomething(), *i = 13;
+ // CHECK-NEXT: call i8* @objc_retainAutoreleasedReturnValue
+ // CHECK: store i32 13
+ // CHECK: store i32 17
+ *i = 17;
+ // CHECK-NEXT: ret void
+}
+
+// CHECK: define void @bridge_of_cf
+void bridge_of_cf(int *i) {
+ // CHECK: store i32 7
+ *i = 7;
+ // CHECK: call i8* @CreateSomething()
+ CFTypeRef cf1 = (__bridge CFTypeRef)CreateSomething();
+ // CHECK-NOT: retain
+ // CHECK: store i32 11
+ *i = 11;
+ // CHECK: call i8* @CreateSomething
+ (__bridge CFTypeRef)CreateSomething(), *i = 13;
+ // CHECK: store i32 13
+ // CHECK-NOT: release
+ // CHECK: store i32 17
+ *i = 17;
+ // CHECK-NEXT: ret void
+}
+
diff --git a/test/CodeGenObjC/arc-compound-stmt.m b/test/CodeGenObjC/arc-compound-stmt.m
new file mode 100644
index 000000000000..946d72f00591
--- /dev/null
+++ b/test/CodeGenObjC/arc-compound-stmt.m
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -fobjc-arc -o - %s
+// rdar://9694706
+
+typedef unsigned long NSUInteger;
+
+@interface NSString
+- (NSString *)stringByAppendingString:(NSString *)aString;
+- (NSString *)substringFromIndex:(NSUInteger)from;
+@end
+
+@interface MyClass
+- (void)inst;
+@end
+
+@implementation MyClass
+
+- (void)inst;
+{
+ NSString *propName;
+
+ NSString *capitalPropName = ({
+ NSString *cap;
+ if (propName)
+ cap = [cap stringByAppendingString:[propName substringFromIndex:1]];
+ cap;
+ });
+}
+
+@end
diff --git a/test/CodeGenObjC/arc-foreach.m b/test/CodeGenObjC/arc-foreach.m
new file mode 100644
index 000000000000..f9d7782fbedd
--- /dev/null
+++ b/test/CodeGenObjC/arc-foreach.m
@@ -0,0 +1,72 @@
+// RUN: %clang_cc1 -fblocks -fobjc-arc -fobjc-nonfragile-abi -fobjc-runtime-has-weak -triple x86_64-apple-darwin -O0 -emit-llvm %s -o %t-64.s
+// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
+// rdar://9503326
+// rdar://9606600
+
+extern void use(id);
+extern void use_block(void (^)(void));
+@class NSArray;
+
+void test0(NSArray *array) {
+ // 'x' should be initialized without a retain.
+ // We should actually do a non-constant capture, and that
+ // capture should require a retain.
+ for (id x in array) {
+ use_block(^{ use(x); });
+ }
+}
+
+// CHECK-LP64: define void @test0(
+// CHECK-LP64: alloca [[ARRAY_T:%.*]]*,
+// CHECK-LP64-NEXT: [[X:%.*]] = alloca i8*,
+// CHECK-LP64-NEXT: [[STATE:%.*]] = alloca [[STATE_T:%.*]],
+// CHECK-LP64-NEXT: alloca [16 x i8*], align 8
+// CHECK-LP64-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
+
+// CHECK-LP64: [[T0:%.*]] = getelementptr inbounds [[STATE_T]]* [[STATE]], i32 0, i32 1
+// CHECK-LP64-NEXT: [[T1:%.*]] = load i8*** [[T0]]
+// CHECK-LP64-NEXT: [[T2:%.*]] = getelementptr i8** [[T1]], i64
+// CHECK-LP64-NEXT: [[T3:%.*]] = load i8** [[T2]]
+// CHECK-LP64-NEXT: store i8* [[T3]], i8** [[X]]
+
+// CHECK-LP64: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
+// CHECK-LP64-NEXT: [[T1:%.*]] = load i8** [[X]]
+// CHECK-LP64-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]])
+// CHECK-LP64-NEXT: store i8* [[T2]], i8** [[T0]]
+// CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]]
+// CHECK-LP64: call void @use_block(
+// CHECK-LP64-NEXT: [[T1:%.*]] = load i8** [[T0]]
+// CHECK-LP64-NEXT: call void @objc_release(i8* [[T1]])
+
+// CHECK-LP64: define internal void @__test0_block_invoke
+// CHECK-LP64: [[BLOCK:%.*]] = bitcast i8* {{%.*}} to [[BLOCK_T]]*
+// CHECK-LP64-NEXT: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
+// CHECK-LP64-NEXT: [[T2:%.*]] = load i8** [[T0]], align 8
+// CHECK-LP64-NEXT: call void @use(i8* [[T2]])
+
+void test1(NSArray *array) {
+ for (__weak id x in array) {
+ use_block(^{ use(x); });
+ }
+}
+
+// CHECK-LP64: define void @test1(
+// CHECK-LP64: alloca [[ARRAY_T:%.*]]*,
+// CHECK-LP64-NEXT: [[X:%.*]] = alloca i8*,
+// CHECK-LP64-NEXT: [[STATE:%.*]] = alloca [[STATE_T:%.*]],
+// CHECK-LP64-NEXT: alloca [16 x i8*], align 8
+// CHECK-LP64-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
+
+// CHECK-LP64: [[T0:%.*]] = getelementptr inbounds [[STATE_T]]* [[STATE]], i32 0, i32 1
+// CHECK-LP64-NEXT: [[T1:%.*]] = load i8*** [[T0]]
+// CHECK-LP64-NEXT: [[T2:%.*]] = getelementptr i8** [[T1]], i64
+// CHECK-LP64-NEXT: [[T3:%.*]] = load i8** [[T2]]
+// CHECK-LP64-NEXT: call i8* @objc_initWeak(i8** [[X]], i8* [[T3]])
+
+// CHECK-LP64: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
+// CHECK-LP64-NEXT: [[T1:%.*]] = call i8* @objc_loadWeak(i8** [[X]])
+// CHECK-LP64-NEXT: call i8* @objc_initWeak(i8** [[T0]], i8* [[T1]])
+// CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to
+// CHECK-LP64: call void @use_block
+// CHECK-LP64-NEXT: call void @objc_destroyWeak(i8** [[T0]])
+// CHECK-LP64-NEXT: call void @objc_destroyWeak(i8** [[X]])
diff --git a/test/CodeGenObjC/arc-ivar-layout.m b/test/CodeGenObjC/arc-ivar-layout.m
new file mode 100644
index 000000000000..cb930fe3d365
--- /dev/null
+++ b/test/CodeGenObjC/arc-ivar-layout.m
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -fobjc-arc -fobjc-nonfragile-abi -fobjc-runtime-has-weak -triple x86_64-apple-darwin -O0 -S %s -o %t-64.s
+// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
+// rdar://8991729
+
+@interface NSObject {
+ id isa;
+}
+@end
+
+@interface AllPointers : NSObject {
+ id foo;
+ id __strong bar;
+ NSObject *bletch;
+}
+@end
+
+@implementation AllPointers
+@end
+// CHECK-LP64: L_OBJC_CLASS_NAME_1:
+// CHECK-LP64-NEXT: .asciz "\003"
+
+@class NSString, NSNumber;
+@interface A : NSObject {
+ NSString *foo;
+ NSNumber *bar;
+ unsigned int bletch;
+ __weak id delegate;
+}
+@end
+
+@interface B : A {
+ unsigned int x;
+ NSString *y;
+ NSString *z;
+}
+@end
+
+@implementation A @end
+
+@implementation B @end
+
+// CHECK-LP64: L_OBJC_CLASS_NAME_15:
+// CHECK-LP64-NEXT: .asciz "\022"
+
diff --git a/test/CodeGenObjC/arc-no-runtime.m b/test/CodeGenObjC/arc-no-runtime.m
new file mode 100644
index 000000000000..39f7da3460e5
--- /dev/null
+++ b/test/CodeGenObjC/arc-no-runtime.m
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-arc -fobjc-nonfragile-abi -emit-llvm %s -o - | FileCheck %s
+
+// rdar://problem/9224855
+void test0() {
+ id x = 0;
+ // CHECK: call void @objc_release(
+}
+
+// CHECK: declare extern_weak void @objc_release(
diff --git a/test/CodeGenObjC/arc-related-result-type.m b/test/CodeGenObjC/arc-related-result-type.m
new file mode 100644
index 000000000000..c51757df5d8d
--- /dev/null
+++ b/test/CodeGenObjC/arc-related-result-type.m
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -fblocks -fobjc-arc -o - %s | FileCheck %s
+
+@interface Test0
+- (id) self;
+@end
+void test0(Test0 *val) {
+ Test0 *x = [val self];
+
+// CHECK: define void @test0(
+// CHECK: [[VAL:%.*]] = alloca [[TEST0:%.*]]*
+// CHECK-NEXT: [[X:%.*]] = alloca [[TEST0]]*
+// CHECK-NEXT: bitcast
+// CHECK-NEXT: call i8* @objc_retain(
+// CHECK-NEXT: bitcast
+// CHECK-NEXT: store
+// CHECK-NEXT: load [[TEST0]]** [[VAL]],
+// CHECK-NEXT: load
+// CHECK-NEXT: bitcast
+// CHECK-NEXT: [[T0:%.*]] = call i8* bitcast (
+// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
+// CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to [[TEST0]]*
+// CHECK-NEXT: store [[TEST0]]* [[T2]], [[TEST0]]** [[X]]
+// CHECK-NEXT: [[T0:%.*]] = load [[TEST0]]** [[X]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST0]]* [[T0]] to i8*
+// CHECK-NEXT: call void @objc_release(i8* [[T1]])
+// CHECK-NEXT: [[T0:%.*]] = load [[TEST0]]** [[VAL]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST0]]* [[T0]] to i8*
+// CHECK-NEXT: call void @objc_release(i8* [[T1]])
+// CHECK-NEXT: ret void
+}
diff --git a/test/CodeGenObjC/arc-unbridged-cast.m b/test/CodeGenObjC/arc-unbridged-cast.m
new file mode 100644
index 000000000000..0f3db09f1ffd
--- /dev/null
+++ b/test/CodeGenObjC/arc-unbridged-cast.m
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -emit-llvm -fobjc-nonfragile-abi -fobjc-arc -o - %s | FileCheck %s
+// rdar://9744349
+
+typedef const struct __CFString * CFStringRef;
+
+@interface I
+@property CFStringRef P;
+- (CFStringRef) CFMeth __attribute__((cf_returns_retained));
+- (CFStringRef) newSomething;
+- (CFStringRef) P __attribute__((cf_returns_retained));
+@end
+
+@implementation I
+@synthesize P;
+- (id) Meth {
+ I* p1 = (id)[p1 P];
+ id p2 = (id)[p1 CFMeth];
+ id p3 = (id)[p1 newSomething];
+ return (id) p1.P;
+}
+- (CFStringRef) CFMeth { return 0; }
+- (CFStringRef) newSomething { return 0; }
+- (CFStringRef) P { return 0; }
+- (void) setP : (CFStringRef)arg {}
+@end
+
+// rdar://9544832
+CFStringRef SomeOtherFunc() __attribute__((cf_returns_retained));
+id MMM()
+{
+ id obj = (id)((CFStringRef) __builtin___CFStringMakeConstantString ("" "Some CF String" ""));
+ if (obj)
+ return (id) SomeOtherFunc();
+ return 0;
+}
+
+// CHECK-NOT: call i8* @objc_retainAutoreleasedReturnValue
diff --git a/test/CodeGenObjC/arc-unopt.m b/test/CodeGenObjC/arc-unopt.m
new file mode 100644
index 000000000000..ed46052af848
--- /dev/null
+++ b/test/CodeGenObjC/arc-unopt.m
@@ -0,0 +1,69 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -fobjc-runtime-has-weak -fblocks -fobjc-arc -o - %s | FileCheck %s
+
+// A test to ensure that we generate fused calls at -O0.
+
+@class Test0;
+Test0 *test0(void) {
+ extern Test0 *test0_helper;
+ return test0_helper;
+
+ // CHECK: [[LD:%.*]] = load [[TEST0:%.*]]** @test0_helper
+ // CHECK-NEXT: [[T0:%.*]] = bitcast [[TEST0]]* [[LD]] to i8*
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleaseReturnValue(i8* [[T0]])
+ // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to [[TEST0]]*
+ // CHECK-NEXT: ret [[TEST0]]* [[T2]]
+}
+
+id test1(void) {
+ extern id test1_helper;
+ return test1_helper;
+
+ // CHECK: [[LD:%.*]] = load i8** @test1_helper
+ // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_retainAutoreleaseReturnValue(i8* [[LD]])
+ // CHECK-NEXT: ret i8* [[T0]]
+}
+
+void test2(void) {
+ // CHECK: [[X:%.*]] = alloca i8*
+ // CHECK-NEXT: store i8* null, i8** [[X]]
+ // CHECK-NEXT: call void @objc_destroyWeak(i8** [[X]])
+ // CHECK-NEXT: ret void
+ __weak id x;
+}
+
+id test3(void) {
+ extern id test3_helper(void);
+ // CHECK: [[T0:%.*]] = call i8* @test3_helper()
+ // CHECK-NEXT: ret i8* [[T0]]
+ return test3_helper();
+}
+
+@interface Test4 { id x; } @end
+@interface Test4_sub : Test4 { id y; } @end
+Test4 *test4(void) {
+ extern Test4_sub *test4_helper(void);
+ // CHECK: [[T0:%.*]] = call [[TEST4S:%.*]]* @test4_helper()
+ // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST4S]]* [[T0]] to [[TEST4:%.*]]*
+ // CHECK-NEXT: ret [[TEST4]]* [[T1]]
+ return test4_helper();
+}
+
+// rdar://problem/9418404
+@class Test5;
+void test5(void) {
+ Test5 *x, *y;
+ if ((x = y))
+ y = 0;
+
+// CHECK: define void @test5()
+// CHECK: [[X:%.*]] = alloca [[TEST5:%.*]]*,
+// CHECK-NEXT: [[Y:%.*]] = alloca [[TEST5:%.*]]*,
+// CHECK-NEXT: store [[TEST5]]* null, [[TEST5]]** [[X]],
+// CHECK-NEXT: store [[TEST5]]* null, [[TEST5]]** [[Y]],
+// CHECK-NEXT: [[T0:%.*]] = load [[TEST5]]** [[Y]],
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST5]]** [[X]] to i8**
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST5]]* [[T0]] to i8*
+// CHECK-NEXT: call void @objc_storeStrong(i8** [[T1]], i8* [[T2]])
+// CHECK-NEXT: [[T3:%.*]] = icmp ne [[TEST5]]* [[T0]], null
+// CHECK-NEXT: br i1 [[T3]],
+}
diff --git a/test/CodeGenObjC/arc-weak-property.m b/test/CodeGenObjC/arc-weak-property.m
new file mode 100644
index 000000000000..c0796046446e
--- /dev/null
+++ b/test/CodeGenObjC/arc-weak-property.m
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -fobjc-runtime-has-weak -fblocks -fobjc-arc -o - %s | FileCheck %s
+// rdar://8899430
+
+@interface WeakPropertyTest {
+ __weak id PROP;
+}
+@property () __weak id PROP;
+@end
+
+@implementation WeakPropertyTest
+@synthesize PROP;
+@end
+
+// CHECK: define internal i8* @"\01-[WeakPropertyTest PROP]"
+// CHECK: [[SELF:%.*]] = alloca [[WPT:%.*]]*,
+// CHECK-NEXT: [[CMD:%.*]] = alloca i8*,
+// CHECK-NEXT: store [[WPT]]* {{%.*}}, [[WPT]]** [[SELF]]
+// CHECK-NEXT: store i8* {{%.*}}, i8** [[CMD]]
+// CHECK-NEXT: [[T0:%.*]] = load [[WPT]]** [[SELF]]
+// CHECK-NEXT: [[T1:%.*]] = load i64* @"OBJC_IVAR_$_WeakPropertyTest.PROP"
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[WPT]]* [[T0]] to i8*
+// CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds i8* [[T2]], i64 [[T1]]
+// CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to i8**
+// CHECK-NEXT: [[T5:%.*]] = call i8* @objc_loadWeakRetained(i8** [[T4]])
+// CHECK-NEXT: [[T6:%.*]] = call i8* @objc_autoreleaseReturnValue(i8* [[T5]])
+// CHECK-NEXT: ret i8* [[T6]]
+
+// CHECK: define internal void @"\01-[WeakPropertyTest setPROP:]"
+// CHECK: [[SELF:%.*]] = alloca [[WPT:%.*]]*,
+// CHECK-NEXT: [[CMD:%.*]] = alloca i8*,
+// CHECK-NEXT: [[PROP:%.*]] = alloca i8*,
+// CHECK-NEXT: store [[WPT]]* {{%.*}}, [[WPT]]** [[SELF]]
+// CHECK-NEXT: store i8* {{%.*}}, i8** [[CMD]]
+// CHECK-NEXT: store i8* {{%.*}}, i8** [[PROP]]
+// CHECK-NEXT: [[V:%.*]] = load i8** [[PROP]]
+// CHECK-NEXT: [[T0:%.*]] = load [[WPT]]** [[SELF]]
+// CHECK-NEXT: [[T1:%.*]] = load i64* @"OBJC_IVAR_$_WeakPropertyTest.PROP"
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[WPT]]* [[T0]] to i8*
+// CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds i8* [[T2]], i64 [[T1]]
+// CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to i8**
+// CHECK-NEXT: call i8* @objc_storeWeak(i8** [[T4]], i8* [[V]])
+// CHECK-NEXT: ret void
+
+// CHECK: define internal void @"\01-[WeakPropertyTest .cxx_destruct]"
+// CHECK: [[SELF:%.*]] = alloca [[WPT:%.*]]*,
+// CHECK-NEXT: [[CMD:%.*]] = alloca i8*,
+// CHECK-NEXT: store [[WPT]]* {{%.*}}, [[WPT]]** [[SELF]]
+// CHECK-NEXT: store i8* {{%.*}}, i8** [[CMD]]
+// CHECK-NEXT: [[T0:%.*]] = load [[WPT]]** [[SELF]]
+// CHECK-NEXT: [[T1:%.*]] = load i64* @"OBJC_IVAR_$_WeakPropertyTest.PROP"
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[WPT]]* [[T0]] to i8*
+// CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds i8* [[T2]], i64 [[T1]]
+// CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to i8**
+// CHECK-NEXT: call void @objc_destroyWeak(i8** [[T4]])
+// CHECK-NEXT: ret void
diff --git a/test/CodeGenObjC/arc.m b/test/CodeGenObjC/arc.m
new file mode 100644
index 000000000000..407b3eb77167
--- /dev/null
+++ b/test/CodeGenObjC/arc.m
@@ -0,0 +1,1554 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -fblocks -fobjc-arc -fobjc-runtime-has-weak -O2 -disable-llvm-optzns -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -fblocks -fobjc-arc -fobjc-runtime-has-weak -o - %s | FileCheck -check-prefix=CHECK-GLOBALS %s
+
+// CHECK: define void @test0
+void test0(id x) {
+ // CHECK: [[X:%.*]] = alloca i8*
+ // CHECK-NEXT: [[PARM:%.*]] = call i8* @objc_retain(i8* {{.*}})
+ // CHECK-NEXT: store i8* [[PARM]], i8** [[X]]
+ // CHECK-NEXT: [[TMP:%.*]] = load i8** [[X]]
+ // CHECK-NEXT: call void @objc_release(i8* [[TMP]])
+ // CHECK-NEXT: ret void
+}
+
+// CHECK: define i8* @test1(i8*
+id test1(id x) {
+ // CHECK: [[RET:%.*]] = alloca i8*
+ // CHECK-NEXT: [[X:%.*]] = alloca i8*
+ // CHECK-NEXT: [[Y:%.*]] = alloca i8*
+ // CHECK-NEXT: alloca i32
+ // CHECK-NEXT: [[PARM:%.*]] = call i8* @objc_retain(i8* {{%.*}})
+ // CHECK-NEXT: store i8* [[PARM]], i8** [[X]]
+ // CHECK-NEXT: store i8* null, i8** [[Y]]
+ // CHECK-NEXT: [[T0:%.*]] = load i8** [[Y]]
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]])
+ // CHECK-NEXT: store i8* [[T1]], i8** [[RET]]
+ // CHECK-NEXT: store i32
+ // CHECK-NEXT: [[T0:%.*]] = load i8** [[Y]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T0]])
+ // CHECK-NEXT: [[T1:%.*]] = load i8** [[X]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T1]])
+ // CHECK-NEXT: [[T0:%.*]] = load i8** [[RET]]
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_autoreleaseReturnValue(i8* [[T0]])
+ // CHECK-NEXT: ret i8* [[T1]]
+ id y;
+ return y;
+}
+
+@interface Test2
++ (void) class_method;
+- (void) inst_method;
+@end
+@implementation Test2
+
+// The self pointer of a class method is not retained.
+// CHECK: define internal void @"\01+[Test2 class_method]"
+// CHECK: alloca
+// CHECK-NEXT: alloca
+// CHECK-NEXT: store
+// CHECK-NEXT: store
+// CHECK-NEXT: ret void
++ (void) class_method {}
+
+// The self pointer of an instance method is not retained.
+// CHECK: define internal void @"\01-[Test2 inst_method]"
+// CHECK: alloca
+// CHECK-NEXT: alloca
+// CHECK-NEXT: store
+// CHECK-NEXT: store
+// CHECK-NEXT: ret void
+- (void) inst_method {}
+@end
+
+@interface Test3
++ (id) alloc;
+- (id) initWith: (int) x;
+- (id) copy;
+@end
+
+// CHECK: define void @test3_unelided()
+void test3_unelided() {
+ extern void test3_helper(void);
+
+ // CHECK: [[X:%.*]] = alloca [[TEST3:%.*]]*
+ // CHECK-NEXT: store [[TEST3]]* null, [[TEST3]]** [[X]], align
+ Test3 *x;
+
+ // Call to +alloc.
+ // CHECK-NEXT: load {{.*}}* @"\01L_OBJC_CLASSLIST_REFERENCES_
+ // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: [[ALLOC:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: call void @objc_release(i8*
+ [Test3 alloc];
+
+ // CHECK-NEXT: [[T0:%.*]] = load [[TEST3]]** [[X]]
+ // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+ // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST3]]* [[T0]] to i8*
+ // CHECK-NEXT: [[COPY:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend {{.*}})(i8* [[T1]],
+ // CHECK-NEXT: call void @objc_release(i8* [[COPY]]) nounwind
+ [x copy];
+
+ // CHECK-NEXT: [[T0:%.*]] = load [[TEST3]]** [[X]]
+ // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST3]]* [[T0]] to i8*
+ // CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind
+ // CHECK-NEXT: ret void
+}
+
+// CHECK: define void @test3()
+void test3() {
+ // CHECK: [[X:%.*]] = alloca i8*
+
+ id x = [[Test3 alloc] initWith: 5];
+
+ // Call to +alloc.
+ // CHECK-NEXT: load {{.*}}* @"\01L_OBJC_CLASSLIST_REFERENCES_
+ // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: [[ALLOC:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
+ // CHECK-NEXT: bitcast
+
+ // Call to -initWith: with elided retain of consumed argument.
+ // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: [[INIT:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*, i32)*)(i8*
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: [[INIT:%.*]] = bitcast
+ // Assignment for initialization, retention elided.
+ // CHECK-NEXT: store i8* [[INIT]], i8** [[X]]
+
+ // Call to -copy.
+ // CHECK-NEXT: [[V:%.*]] = load i8** [[X]]
+ // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+ // CHECK-NEXT: [[COPY:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend {{.*}})(i8* [[V]],
+
+ // Assignment to x.
+ // CHECK-NEXT: [[TMP:%.*]] = load i8** [[X]]
+ // CHECK-NEXT: store i8* [[COPY]], i8** [[X]]
+ // CHECK-NEXT: call void @objc_release(i8* [[TMP]]) nounwind
+
+ x = [x copy];
+
+ // Cleanup for x.
+ // CHECK-NEXT: [[TMP:%.*]] = load i8** [[X]]
+ // CHECK-NEXT: call void @objc_release(i8* [[TMP]]) nounwind
+
+ // CHECK-NEXT: ret void
+}
+
+// CHECK: define i8* @test4()
+id test4() {
+ // Call to +alloc.
+ // CHECK: load {{.*}}* @"\01L_OBJC_CLASSLIST_REFERENCES_
+ // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: [[ALLOC:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
+ // CHECK-NEXT: [[ALLOC:%.*]] = bitcast
+
+ // Call to -initWith: with elided retain of consumed argument.
+ // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+ // CHECK-NEXT: [[ALLOC:%.*]] = bitcast
+ // CHECK-NEXT: [[INIT:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*, i32)*)(i8* [[ALLOC]],
+
+ // Initialization of return value, occuring within full-expression.
+ // Retain/release elided.
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: [[INIT:%.*]] = bitcast
+ // CHECK-NEXT: [[RET:%.*]] = call i8* @objc_autoreleaseReturnValue(i8* [[INIT]])
+
+ // CHECK-NEXT: ret i8* [[RET]]
+
+ return [[Test3 alloc] initWith: 6];
+}
+
+@interface Test5 {
+@public
+ id var;
+}
+@end
+
+// CHECK: define void @test5
+void test5(Test5 *x, id y) {
+ // Prologue.
+ // CHECK: [[X:%.*]] = alloca [[TEST5:%.*]]*,
+ // CHECK-NEXT: [[Y:%.*]] = alloca i8*
+ // CHECK-NEXT: bitcast [[TEST5]]* {{%.*}} to i8*
+ // CHECK-NEXT: call i8* @objc_retain
+ // CHECK-NEXT: [[PARMX:%.*]] = bitcast i8* {{%.*}} to [[TEST5]]*
+ // CHECK-NEXT: store [[TEST5]]* [[PARMX]], [[TEST5]]** [[X]]
+ // CHECK-NEXT: call i8* @objc_retain
+ // CHECK-NEXT: store
+
+ // CHECK-NEXT: load [[TEST5]]** [[X]]
+ // CHECK-NEXT: load i64* @"OBJC_IVAR_$_Test5.var"
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: getelementptr
+ // CHECK-NEXT: [[VAR:%.*]] = bitcast
+ // CHECK-NEXT: [[TMP:%.*]] = load i8** [[VAR]]
+ // CHECK-NEXT: store i8* null, i8** [[VAR]]
+ // CHECK-NEXT: call void @objc_release(i8* [[TMP]]) nounwind
+ x->var = 0;
+
+ // CHECK-NEXT: [[YVAL:%.*]] = load i8** [[Y]]
+ // CHECK-NEXT: load [[TEST5]]** [[X]]
+ // CHECK-NEXT: load i64* @"OBJC_IVAR_$_Test5.var"
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: getelementptr
+ // CHECK-NEXT: [[VAR:%.*]] = bitcast
+ // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_retain(i8* [[YVAL]]) nounwind
+ // CHECK-NEXT: [[TMP:%.*]] = load i8** [[VAR]]
+ // CHECK-NEXT: store i8* [[T0]], i8** [[VAR]]
+ // CHECK-NEXT: call void @objc_release(i8* [[TMP]]) nounwind
+ x->var = y;
+
+ // Epilogue.
+ // CHECK-NEXT: [[TMP:%.*]] = load i8** [[Y]]
+ // CHECK-NEXT: call void @objc_release(i8* [[TMP]]) nounwind
+ // CHECK-NEXT: [[T0:%.*]] = load [[TEST5]]** [[X]]
+ // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST5]]* [[T0]] to i8*
+ // CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind
+ // CHECK-NEXT: ret void
+}
+
+id test6_helper(void) __attribute__((ns_returns_retained));
+// CHECK: define void @test6()
+void test6() {
+ // CHECK: [[X:%.*]] = alloca i8*
+ // CHECK-NEXT: [[CALL:%.*]] = call i8* @test6_helper()
+ // CHECK-NEXT: store i8* [[CALL]], i8** [[X]]
+ // CHECK-NEXT: [[T1:%.*]] = load i8** [[X]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind, !clang.imprecise_release
+ // CHECK-NEXT: ret void
+ id x = test6_helper();
+}
+
+void test7_helper(id __attribute__((ns_consumed)));
+// CHECK: define void @test7()
+void test7() {
+ // CHECK: [[X:%.*]] = alloca i8*
+ // CHECK-NEXT: store i8* null, i8** [[X]]
+ // CHECK-NEXT: [[T0:%.*]] = load i8** [[X]]
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]]) nounwind
+ // CHECK-NEXT: call void @test7_helper(i8* [[T1]])
+ // CHECK-NEXT: [[T1:%.*]] = load i8** [[X]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind, !clang.imprecise_release
+ // CHECK-NEXT: ret void
+ id x;
+ test7_helper(x);
+}
+
+id test8_helper(void) __attribute__((ns_returns_retained));
+void test8() {
+ __unsafe_unretained id x = test8_helper();
+ // CHECK: [[X:%.*]] = alloca i8*
+ // CHECK-NEXT: [[T0:%.*]] = call i8* @test8_helper()
+ // CHECK-NEXT: store i8* [[T0]], i8** [[X]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind
+ // CHECK-NOT: imprecise_release
+ // CHECK-NEXT: ret void
+}
+
+id test9_helper(void) __attribute__((ns_returns_retained));
+void test9() {
+ id x __attribute__((objc_precise_lifetime)) = test9_helper();
+ x = 0;
+ // CHECK: [[X:%.*]] = alloca i8*
+ // CHECK-NEXT: [[CALL:%.*]] = call i8* @test9_helper()
+ // CHECK-NEXT: store i8* [[CALL]], i8** [[X]]
+
+ // CHECK-NEXT: [[T1:%.*]] = load i8** [[X]]
+ // CHECK-NEXT: store i8* null, i8** [[X]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind, !clang.imprecise_release
+
+ // CHECK-NEXT: [[T1:%.*]] = load i8** [[X]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind
+ // CHECK-NOT: clang.imprecise_release
+
+ // CHECK-NEXT: ret void
+}
+
+@interface Test10
+@property (retain) Test10 *me;
+@end
+void test10() {
+ Test10 *x;
+ id y = x.me.me;
+
+ // CHECK: define void @test10()
+ // CHECK: [[X:%.*]] = alloca [[TEST10:%.*]]*, align
+ // CHECK-NEXT: [[Y:%.*]] = alloca i8*, align
+ // CHECK-NEXT: store [[TEST10]]* null, [[TEST10]]** [[X]]
+ // CHECK-NEXT: load [[TEST10]]** [[X]], align
+ // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_{{[0-9]*}}"
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: [[T0:%.*]] = call [[TEST10]]* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
+ // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST10]]* [[T0]] to i8*
+ // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
+ // CHECK-NEXT: [[V:%.*]] = bitcast i8* [[T2]] to [[TEST10]]*
+ // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_{{[0-9]*}}"
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: [[T0:%.*]] = call [[TEST10]]* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
+ // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST10]]* [[T0]] to i8*
+ // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
+ // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST10]]*
+ // CHECK-NEXT: [[T4:%.*]] = bitcast [[TEST10]]* [[T3]] to i8*
+ // CHECK-NEXT: store i8* [[T4]], i8** [[Y]]
+ // CHECK-NEXT: [[T0:%.*]] = bitcast [[TEST10]]* [[V]] to i8*
+ // CHECK-NEXT: call void @objc_release(i8* [[T0]])
+ // CHECK-NEXT: [[T0:%.*]] = load i8** [[Y]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T0]])
+ // CHECK-NEXT: [[T0:%.*]] = load [[TEST10]]** [[X]]
+ // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST10]]* [[T0]] to i8*
+ // CHECK-NEXT: call void @objc_release(i8* [[T1]])
+ // CHECK-NEXT: ret void
+}
+
+void test11(id (*f)(void) __attribute__((ns_returns_retained))) {
+ // CHECK: define void @test11(
+ // CHECK: [[F:%.*]] = alloca i8* ()*, align
+ // CHECK-NEXT: [[X:%.*]] = alloca i8*, align
+ // CHECK-NEXT: store i8* ()* {{%.*}}, i8* ()** [[F]], align
+ // CHECK-NEXT: [[T0:%.*]] = load i8* ()** [[F]], align
+ // CHECK-NEXT: [[T1:%.*]] = call i8* [[T0]]()
+ // CHECK-NEXT: store i8* [[T1]], i8** [[X]], align
+ // CHECK-NEXT: [[T3:%.*]] = load i8** [[X]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T3]]) nounwind, !clang.imprecise_release
+ // CHECK-NEXT: ret void
+ id x = f();
+}
+
+void test12(void) {
+ extern id test12_helper(void);
+
+ // CHECK: define void @test12()
+ // CHECK: [[X:%.*]] = alloca i8*, align
+ // CHECK-NEXT: [[Y:%.*]] = alloca i8*, align
+
+ __weak id x = test12_helper();
+ // CHECK-NEXT: [[T0:%.*]] = call i8* @test12_helper()
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
+ // CHECK-NEXT: call i8* @objc_initWeak(i8** [[X]], i8* [[T1]])
+ // CHECK-NEXT: call void @objc_release(i8* [[T1]])
+
+ x = test12_helper();
+ // CHECK-NEXT: [[T0:%.*]] = call i8* @test12_helper()
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
+ // CHECK-NEXT: call i8* @objc_storeWeak(i8** [[X]], i8* [[T1]])
+ // CHECK-NEXT: call void @objc_release(i8* [[T1]])
+
+ id y = x;
+ // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_loadWeakRetained(i8** [[X]])
+ // CHECK-NEXT: store i8* [[T2]], i8** [[Y]], align
+
+ // CHECK-NEXT: [[T4:%.*]] = load i8** [[Y]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T4]]) nounwind, !clang.imprecise_release
+ // CHECK-NEXT: call void @objc_destroyWeak(i8** [[X]])
+ // CHECK-NEXT: ret void
+}
+
+// Indirect consuming calls.
+void test13(void) {
+ // CHECK: define void @test13()
+ // CHECK: [[X:%.*]] = alloca i8*, align
+ // CHECK-NEXT: store i8* null, i8** [[X]], align
+ id x;
+
+ typedef void fnty(id __attribute__((ns_consumed)));
+ extern fnty *test13_func;
+ // CHECK-NEXT: [[FN:%.*]] = load void (i8*)** @test13_func, align
+ // CHECK-NEXT: [[X_VAL:%.*]] = load i8** [[X]], align
+ // CHECK-NEXT: [[X_TMP:%.*]] = call i8* @objc_retain(i8* [[X_VAL]]) nounwind
+ // CHECK-NEXT: call void [[FN]](i8* [[X_TMP]])
+ test13_func(x);
+
+ extern fnty ^test13_block;
+ // CHECK-NEXT: [[TMP:%.*]] = load void (i8*)** @test13_block, align
+ // CHECK-NEXT: [[BLOCK:%.*]] = bitcast void (i8*)* [[TMP]] to [[BLOCKTY:%.*]]*
+ // CHECK-NEXT: [[BLOCK_FN_PTR:%.*]] = getelementptr inbounds [[BLOCKTY]]* [[BLOCK]], i32 0, i32 3
+ // CHECK-NEXT: [[BLOCK_OPAQUE:%.*]] = bitcast [[BLOCKTY]]* [[BLOCK]] to i8*
+ // CHECK-NEXT: [[X_VAL:%.*]] = load i8** [[X]], align
+ // CHECK-NEXT: [[X_TMP:%.*]] = call i8* @objc_retain(i8* [[X_VAL]]) nounwind
+ // CHECK-NEXT: [[BLOCK_FN_TMP:%.*]] = load i8** [[BLOCK_FN_PTR]]
+ // CHECK-NEXT: [[BLOCK_FN:%.*]] = bitcast i8* [[BLOCK_FN_TMP]] to void (i8*, i8*)*
+ // CHECK-NEXT: call void [[BLOCK_FN]](i8* [[BLOCK_OPAQUE]], i8* [[X_TMP]])
+ test13_block(x);
+
+ // CHECK-NEXT: [[T0:%.*]] = load i8** [[X]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind
+ // CHECK-NEXT: ret void
+}
+
+@interface Test16_super @end
+@interface Test16 : Test16_super {
+ id z;
+}
+@property (assign) int x;
+@property (retain) id y;
+- (void) dealloc;
+@end
+@implementation Test16
+@synthesize x;
+@synthesize y;
+- (void) dealloc {
+ // CHECK: define internal void @"\01-[Test16 dealloc]"(
+ // CHECK: [[SELF:%.*]] = alloca [[TEST16:%.*]]*, align
+ // CHECK-NEXT: [[CMD:%.*]] = alloca i8*, align
+ // CHECK-NEXT: alloca
+ // CHECK-NEXT: store [[TEST16]]* {{%.*}}, [[TEST16]]** [[SELF]], align
+ // CHECK-NEXT: store i8* {{%.*}}, i8** [[CMD]]
+ // CHECK-NEXT: [[BASE:%.*]] = load [[TEST16]]** [[SELF]]
+
+ // Call super.
+ // CHECK-NEXT: [[BASE2:%.*]] = bitcast [[TEST16]]* [[BASE]] to i8*
+ // CHECK-NEXT: [[T0:%.*]] = getelementptr
+ // CHECK-NEXT: store i8* [[BASE2]], i8** [[T0]]
+ // CHECK-NEXT: load {{%.*}}** @"\01L_OBJC_CLASSLIST_SUP_REFS_$_
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: getelementptr
+ // CHECK-NEXT: store
+ // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+ // CHECK-NEXT: call void bitcast (i8* ({{.*}})* @objc_msgSendSuper2 to void (
+ // CHECK-NEXT: ret void
+}
+
+// .cxx_destruct
+ // CHECK: define internal void @"\01-[Test16 .cxx_destruct]"(
+ // CHECK: [[SELF:%.*]] = alloca [[TEST16:%.*]]*, align
+ // CHECK-NEXT: [[CMD:%.*]] = alloca i8*, align
+ // CHECK-NEXT: store [[TEST16]]* {{%.*}}, [[TEST16]]** [[SELF]], align
+ // CHECK-NEXT: store i8* {{%.*}}, i8** [[CMD]]
+ // CHECK-NEXT: [[BASE:%.*]] = load [[TEST16]]** [[SELF]]
+
+ // Destroy y.
+ // CHECK-NEXT: [[Y_OFF:%.*]] = load i64* @"OBJC_IVAR_$_Test16.y"
+ // CHECK-NEXT: [[T0:%.*]] = bitcast [[TEST16]]* [[BASE]] to i8*
+ // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds i8* [[T0]], i64 [[Y_OFF]]
+ // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to i8**
+ // CHECK-NEXT: call void @objc_storeStrong(i8** [[T2]], i8* null) nounwind
+
+ // Destroy z.
+ // CHECK-NEXT: [[Z_OFF:%.*]] = load i64* @"OBJC_IVAR_$_Test16.z"
+ // CHECK-NEXT: [[T0:%.*]] = bitcast [[TEST16]]* [[BASE]] to i8*
+ // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds i8* [[T0]], i64 [[Z_OFF]]
+ // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to i8**
+ // CHECK-NEXT: call void @objc_storeStrong(i8** [[T2]], i8* null) nounwind
+
+ // CHECK-NEXT: ret void
+
+@end
+
+// This shouldn't crash.
+@interface Test17A
+@property (assign) int x;
+@end
+@interface Test17B : Test17A
+@end
+@implementation Test17B
+- (int) x { return super.x + 1; }
+@end
+
+// This shouldn't crash.
+void test18(id (^maker)(void)) {
+ maker();
+}
+
+void test19() {
+ // CHECK: define void @test19()
+ // CHECK: [[X:%.*]] = alloca [5 x i8*], align 16
+ // CHECK-NEXT: [[T0:%.*]] = bitcast [5 x i8*]* [[X]] to i8*
+ // CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 40, i32 16, i1 false)
+ id x[5];
+
+ extern id test19_helper(void);
+ x[2] = test19_helper();
+
+ // CHECK-NEXT: [[CALL:%.*]] = call i8* @test19_helper()
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[CALL]]) nounwind
+ // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [5 x i8*]* [[X]], i32 0, i64 2
+ // CHECK-NEXT: [[T0:%.*]] = load i8** [[SLOT]]
+ // CHECK-NEXT: store i8* [[T1]], i8** [[SLOT]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind
+
+ // CHECK-NEXT: [[BEGIN:%.*]] = getelementptr inbounds [5 x i8*]* [[X]], i32 0, i32 0
+ // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds i8** [[BEGIN]], i64 5
+ // CHECK-NEXT: br label
+
+ // CHECK: [[AFTER:%.*]] = phi i8** [ [[END]], {{%.*}} ], [ [[NEXT:%.*]], {{%.*}} ]
+ // CHECK-NEXT: [[CUR:%.*]] = getelementptr inbounds i8** [[AFTER]], i64 -1
+ // CHECK-NEXT: [[T0:%.*]] = load i8** [[CUR]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind, !clang.imprecise_release
+ // CHECK-NEXT: [[EQ:%.*]] = icmp eq i8** [[CUR]], [[BEGIN]]
+ // CHECK-NEXT: br i1 [[EQ]],
+
+ // CHECK: ret void
+}
+
+void test20(unsigned n) {
+ // CHECK: define void @test20
+ // CHECK: [[N:%.*]] = alloca i32, align 4
+ // CHECK-NEXT: [[SAVED_STACK:%.*]] = alloca i8*
+ // CHECK-NEXT: store i32 {{%.*}}, i32* [[N]], align 4
+
+ id x[n];
+
+ // Capture the VLA size.
+ // CHECK-NEXT: [[T0:%.*]] = load i32* [[N]], align 4
+ // CHECK-NEXT: [[DIM:%.*]] = zext i32 [[T0]] to i64
+
+ // Save the stack pointer.
+ // CHECK-NEXT: [[T0:%.*]] = call i8* @llvm.stacksave()
+ // CHECK-NEXT: store i8* [[T0]], i8** [[SAVED_STACK]]
+
+ // Allocate the VLA.
+ // CHECK-NEXT: [[VLA:%.*]] = alloca i8*, i64 [[DIM]], align 16
+
+ // Zero-initialize.
+ // CHECK-NEXT: [[T0:%.*]] = bitcast i8** [[VLA]] to i8*
+ // CHECK-NEXT: [[T1:%.*]] = mul nuw i64 [[DIM]], 8
+ // CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 [[T1]], i32 8, i1 false)
+
+ // Destroy.
+ // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds i8** [[VLA]], i64 [[DIM]]
+ // CHECK-NEXT: [[EMPTY:%.*]] = icmp eq i8** [[VLA]], [[END]]
+ // CHECK-NEXT: br i1 [[EMPTY]]
+
+ // CHECK: [[AFTER:%.*]] = phi i8** [ [[END]], {{%.*}} ], [ [[CUR:%.*]], {{%.*}} ]
+ // CHECK-NEXT: [[CUR:%.*]] = getelementptr inbounds i8** [[AFTER]], i64 -1
+ // CHECK-NEXT: [[T0:%.*]] = load i8** [[CUR]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind, !clang.imprecise_release
+ // CHECK-NEXT: [[EQ:%.*]] = icmp eq i8** [[CUR]], [[VLA]]
+ // CHECK-NEXT: br i1 [[EQ]],
+
+ // CHECK: [[T0:%.*]] = load i8** [[SAVED_STACK]]
+ // CHECK-NEXT: call void @llvm.stackrestore(i8* [[T0]])
+ // CHECK-NEXT: ret void
+}
+
+void test21(unsigned n) {
+ // CHECK: define void @test21
+ // CHECK: [[N:%.*]] = alloca i32, align 4
+ // CHECK-NEXT: [[SAVED_STACK:%.*]] = alloca i8*
+ // CHECK-NEXT: store i32 {{%.*}}, i32* [[N]], align 4
+
+ id x[2][n][3];
+
+ // Capture the VLA size.
+ // CHECK-NEXT: [[T0:%.*]] = load i32* [[N]], align 4
+ // CHECK-NEXT: [[DIM:%.*]] = zext i32 [[T0]] to i64
+
+ // CHECK-NEXT: [[T0:%.*]] = call i8* @llvm.stacksave()
+ // CHECK-NEXT: store i8* [[T0]], i8** [[SAVED_STACK]]
+
+
+ // Allocate the VLA.
+ // CHECK-NEXT: [[T0:%.*]] = mul nuw i64 2, [[DIM]]
+ // CHECK-NEXT: [[VLA:%.*]] = alloca [3 x i8*], i64 [[T0]], align 16
+
+ // Zero-initialize.
+ // CHECK-NEXT: [[T0:%.*]] = bitcast [3 x i8*]* [[VLA]] to i8*
+ // CHECK-NEXT: [[T1:%.*]] = mul nuw i64 2, [[DIM]]
+ // CHECK-NEXT: [[T2:%.*]] = mul nuw i64 [[T1]], 24
+ // CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 [[T2]], i32 8, i1 false)
+
+ // Destroy.
+ // CHECK-NEXT: [[T0:%.*]] = mul nuw i64 2, [[DIM]]
+ // CHECK-NEXT: [[BEGIN:%.*]] = getelementptr inbounds [3 x i8*]* [[VLA]], i32 0, i32 0
+ // CHECK-NEXT: [[T1:%.*]] = mul nuw i64 [[T0]], 3
+ // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds i8** [[BEGIN]], i64 [[T1]]
+ // CHECK-NEXT: [[EMPTY:%.*]] = icmp eq i8** [[BEGIN]], [[END]]
+ // CHECK-NEXT: br i1 [[EMPTY]]
+
+ // CHECK: [[AFTER:%.*]] = phi i8** [ [[END]], {{%.*}} ], [ [[CUR:%.*]], {{%.*}} ]
+ // CHECK-NEXT: [[CUR:%.*]] = getelementptr inbounds i8** [[AFTER]], i64 -1
+ // CHECK-NEXT: [[T0:%.*]] = load i8** [[CUR]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind, !clang.imprecise_release
+ // CHECK-NEXT: [[EQ:%.*]] = icmp eq i8** [[CUR]], [[BEGIN]]
+ // CHECK-NEXT: br i1 [[EQ]],
+
+ // CHECK: [[T0:%.*]] = load i8** [[SAVED_STACK]]
+ // CHECK-NEXT: call void @llvm.stackrestore(i8* [[T0]])
+ // CHECK-NEXT: ret void
+}
+
+void test22(_Bool cond) {
+ id test22_helper(void) __attribute__((ns_returns_retained));
+
+ // CHECK: define void @test22(
+ // CHECK: [[COND:%.*]] = alloca i8,
+ // CHECK-NEXT: [[X:%.*]] = alloca i8*,
+ // CHECK-NEXT: [[RELCOND:%.*]] = alloca i1
+ // CHECK-NEXT: [[RELVAL:%.*]] = alloca i8*
+ // CHECK-NEXT: store i1 false, i1* [[RELCOND]]
+ // CHECK-NEXT: zext
+ // CHECK-NEXT: store
+ // CHECK-NEXT: [[T0:%.*]] = load i8* [[COND]]
+ // CHECK-NEXT: [[T1:%.*]] = trunc i8 [[T0]] to i1
+ // CHECK-NEXT: br i1 [[T1]],
+ // CHECK: br label
+ // CHECK: [[CALL:%.*]] = call i8* @test22_helper()
+ // CHECK-NEXT: store i1 true, i1* [[RELCOND]]
+ // CHECK-NEXT: store i8* [[CALL]], i8** [[RELVAL]]
+ // CHECK-NEXT: br label
+ // CHECK: [[T0:%.*]] = phi i8* [ null, {{%.*}} ], [ [[CALL]], {{%.*}} ]
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]]) nounwind
+ // CHECK-NEXT: store i8* [[T1]], i8** [[X]],
+ // CHECK-NEXT: [[REL:%.*]] = load i1* [[RELCOND]]
+ // CHECK-NEXT: br i1 [[REL]],
+ // CHECK: [[T0:%.*]] = load i8** [[RELVAL]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind
+ // CHECK-NEXT: br label
+ // CHECK: [[T0:%.*]] = load i8** [[X]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind
+ // CHECK-NEXT: ret void
+ id x = (cond ? 0 : test22_helper());
+}
+
+// rdar://problem/8922540
+// Note that we no longer emit .release_ivars flags.
+// CHECK-GLOBALS: @"\01l_OBJC_CLASS_RO_$_Test23" = internal global [[RO_T:%.*]] { i32 134,
+@interface Test23 { id x; } @end
+@implementation Test23 @end
+
+// CHECK-GLOBALS: @"\01l_OBJC_CLASS_RO_$_Test24" = internal global [[RO_T:%.*]] { i32 130,
+@interface Test24 {} @end
+@implementation Test24 @end
+
+int (^test25(int x))(void) {
+ // CHECK: define i32 ()* @test25(
+ // CHECK: [[X:%.*]] = alloca i32,
+ // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
+ // CHECK-NEXT: store i32 {{%.*}}, i32* [[X]]
+ // CHECK: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to i32 ()*
+ // CHECK-NEXT: [[T1:%.*]] = bitcast i32 ()* [[T0]] to i8*
+ // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]]) nounwind
+ // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to i32 ()*
+ // CHECK-NEXT: [[T4:%.*]] = bitcast i32 ()* [[T3]] to i8*
+ // CHECK-NEXT: [[T5:%.*]] = call i8* @objc_autoreleaseReturnValue(i8* [[T4]]) nounwind
+ // CHECK-NEXT: [[T6:%.*]] = bitcast i8* [[T5]] to i32 ()*
+ // CHECK-NEXT: ret i32 ()* [[T6]]
+ return ^{ return x; };
+}
+
+// rdar://problem/8941012
+@interface Test26 { id x[4]; } @end
+@implementation Test26 @end
+// CHECK: define internal void @"\01-[Test26 .cxx_destruct]"(
+// CHECK: [[SELF:%.*]] = load [[TEST26:%.*]]**
+// CHECK-NEXT: [[OFFSET:%.*]] = load i64* @"OBJC_IVAR_$_Test26.x"
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[TEST26]]* [[SELF]] to i8*
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds i8* [[T0]], i64 [[OFFSET]]
+// CHECK-NEXT: [[X:%.*]] = bitcast i8* [[T1]] to [4 x i8*]*
+// CHECK-NEXT: [[BEGIN:%.*]] = getelementptr inbounds [4 x i8*]* [[X]], i32 0, i32 0
+// CHECK-NEXT: [[END:%.*]] = getelementptr inbounds i8** [[BEGIN]], i64 4
+// CHECK-NEXT: br label
+// CHECK: [[PAST:%.*]] = phi i8** [ [[END]], {{%.*}} ], [ [[CUR:%.*]], {{%.*}} ]
+// CHECK-NEXT: [[CUR]] = getelementptr inbounds i8** [[PAST]], i64 -1
+// CHECK-NEXT: call void @objc_storeStrong(i8** [[CUR]], i8* null)
+// CHECK-NEXT: [[ISDONE:%.*]] = icmp eq i8** [[CUR]], [[BEGIN]]
+// CHECK-NEXT: br i1 [[ISDONE]],
+// CHECK: ret void
+
+// Check that 'init' retains self.
+@interface Test27
+- (id) init;
+@end
+@implementation Test27
+- (id) init { return self; }
+// CHECK: define internal i8* @"\01-[Test27 init]"
+// CHECK: [[RET:%.*]] = alloca i8*,
+// CHECK-NEXT: [[SELF:%.*]] = alloca [[TEST27:%.*]]*,
+// CHECK-NEXT: [[CMD:%.*]] = alloca i8*,
+// CHECK-NEXT: [[DEST:%.*]] = alloca i32
+// CHECK-NEXT: store [[TEST27]]* {{%.*}}, [[TEST27]]** [[SELF]]
+// CHECK-NEXT: store i8* {{%.*}}, i8** [[CMD]]
+// CHECK-NEXT: [[T0:%.*]] = load [[TEST27]]** [[SELF]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST27]]* [[T0]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]])
+// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]]
+// CHECK-NEXT: [[T2:%.*]] = bitcast
+// CHECK-NEXT: store i8* [[T2]], i8** [[RET]]
+// CHECK-NEXT: store i32 {{[0-9]+}}, i32* [[DEST]]
+// CHECK-NEXT: [[T0:%.*]] = load [[TEST27]]** [[SELF]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST27]]* [[T0]] to i8*
+// CHECK-NEXT: call void @objc_release(i8* [[T1]])
+// CHECK-NEXT: [[T0:%.*]] = load i8** [[RET]]
+// CHECK-NEXT: ret i8* [[T0]]
+
+@end
+
+// rdar://problem/8087194
+@interface Test28
+@property (copy) id prop;
+@end
+@implementation Test28
+@synthesize prop;
+@end
+// CHECK: define internal void @"\01-[Test28 .cxx_destruct]"
+// CHECK: [[SELF:%.*]] = load [[TEST28:%.*]]**
+// CHECK-NEXT: [[OFFSET:%.*]] = load i64* @"OBJC_IVAR_$_Test28.prop"
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[TEST28]]* [[SELF]] to i8*
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds i8* [[T0]], i64 [[OFFSET]]
+// CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to i8**
+// CHECK-NEXT: call void @objc_storeStrong(i8** [[T2]], i8* null)
+// CHECK-NEXT: ret void
+
+@interface Test29_super
+- (id) initWithAllocator: (id) allocator;
+@end
+@interface Test29 : Test29_super
+- (id) init;
+- (id) initWithAllocator: (id) allocator;
+@end
+@implementation Test29
+static id _test29_allocator = 0;
+- (id) init {
+// CHECK: define internal i8* @"\01-[Test29 init]"([[TEST29:%.*]]* {{%.*}},
+// CHECK: [[RET:%.*]] = alloca i8*, align 8
+// CHECK-NEXT: [[SELF:%.*]] = alloca [[TEST29]]*, align 8
+// CHECK-NEXT: [[CMD:%.*]] = alloca i8*, align 8
+// CHECK-NEXT: [[CLEANUP:%.*]] = alloca i32
+// CHECK-NEXT: store [[TEST29]]* {{%.*}}, [[TEST29]]** [[SELF]]
+// CHECK-NEXT: store i8* {{%.*}}, i8** [[CMD]]
+
+// Evaluate arguments. Note that the send argument is evaluated
+// before the zeroing of self.
+// CHECK-NEXT: [[T0:%.*]] = load [[TEST29]]** [[SELF]], align 8
+// CHECK-NEXT: [[T1:%.*]] = load i8** @_test29_allocator, align 8
+
+// Implicit null of 'self', i.e. direct transfer of ownership.
+// CHECK-NEXT: store [[TEST29]]* null, [[TEST29]]** [[SELF]]
+
+// Actual message send.
+// CHECK-NEXT: [[T2:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+// CHECK-NEXT: [[T3:%.*]] = bitcast [[TEST29]]* [[T0]] to i8*
+// CHECK-NEXT: [[CALL:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*, i8*)*)(i8* [[T3]], i8* [[T2]], i8* [[T1]])
+
+// Implicit write of result back into 'self'. This is not supposed to
+// be detectable because we're supposed to ban accesses to the old
+// self value past the delegate init call.
+// CHECK-NEXT: [[T0:%.*]] = bitcast i8* [[CALL]] to [[TEST29]]*
+// CHECK-NEXT: store [[TEST29]]* [[T0]], [[TEST29]]** [[SELF]]
+
+// Return statement.
+// CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[CALL]]
+// CHECK-NEXT: [[CALL:%.*]] = bitcast
+// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[CALL]]) nounwind
+// CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast
+// CHECK-NEXT: store i8* [[T1]], i8** [[RET]]
+// CHECK-NEXT: store i32 1, i32* [[CLEANUP]]
+
+// Cleanup.
+// CHECK-NEXT: [[T0:%.*]] = load [[TEST29]]** [[SELF]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST29]]* [[T0]] to i8*
+// CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind, !clang.imprecise_release
+
+// Return.
+// CHECK-NEXT: [[T0:%.*]] = load i8** [[RET]]
+// CHECK-NEXT: ret i8* [[T0]]
+ return [self initWithAllocator: _test29_allocator];
+}
+- (id) initWithAllocator: (id) allocator {
+// CHECK: define internal i8* @"\01-[Test29 initWithAllocator:]"(
+// CHECK: [[RET:%.*]] = alloca i8*, align 8
+// CHECK-NEXT: [[SELF:%.*]] = alloca [[TEST29]]*, align 8
+// CHECK-NEXT: [[CMD:%.*]] = alloca i8*, align 8
+// CHECK-NEXT: [[ALLOCATOR:%.*]] = alloca i8*, align 8
+// CHECK-NEXT: alloca
+// CHECK-NEXT: [[CLEANUP:%.*]] = alloca i32
+// CHECK-NEXT: store [[TEST29]]* {{%.*}}, [[TEST29]]** [[SELF]]
+// CHECK-NEXT: store i8* {{%.*}}, i8** [[CMD]]
+// CHECK-NEXT: [[T0:%.*]] = call i8* @objc_retain(i8* {{%.*}})
+// CHECK-NEXT: store i8* [[T0]], i8** [[ALLOCATOR]]
+
+// Evaluate arguments. Note that the send argument is evaluated
+// before the zeroing of self.
+// CHECK-NEXT: [[T0:%.*]] = load [[TEST29]]** [[SELF]]
+// CHECK-NEXT: [[T1:%.*]] = load i8** [[ALLOCATOR]], align 8
+
+// Implicit null of 'self', i.e. direct transfer of ownership.
+// CHECK-NEXT: store [[TEST29]]* null, [[TEST29]]** [[SELF]]
+
+// Actual message send.
+// CHECK: [[CALL:%.*]] = call {{.*}} @objc_msgSendSuper2
+
+// Implicit write of result back into 'self'. This is not supposed to
+// be detectable because we're supposed to ban accesses to the old
+// self value past the delegate init call.
+// CHECK-NEXT: [[T0:%.*]] = bitcast i8* [[CALL]] to [[TEST29]]*
+// CHECK-NEXT: store [[TEST29]]* [[T0]], [[TEST29]]** [[SELF]]
+
+// Assignment.
+// CHECK-NEXT: [[T0:%.*]] = bitcast i8* [[CALL]] to [[TEST29]]*
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST29]]* [[T0]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]]) nounwind
+// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST29]]*
+// CHECK-NEXT: [[T4:%.*]] = load [[TEST29]]** [[SELF]], align
+// CHECK-NEXT: store [[TEST29]]* [[T3]], [[TEST29]]** [[SELF]], align
+// CHECK-NEXT: [[T5:%.*]] = bitcast [[TEST29]]* [[T4]] to i8*
+// CHECK-NEXT: call void @objc_release(i8* [[T5]])
+
+// Return statement.
+// CHECK-NEXT: [[T0:%.*]] = load [[TEST29]]** [[SELF]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST29]]* [[T0]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]]) nounwind
+// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]]
+// CHECK-NEXT: [[T2:%.*]] = bitcast
+// CHECK-NEXT: store i8* [[T2]], i8** [[RET]]
+// CHECK-NEXT: store i32 1, i32* [[CLEANUP]]
+
+// Cleanup.
+// CHECK-NEXT: [[T0:%.*]] = load i8** [[ALLOCATOR]]
+// CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind, !clang.imprecise_release
+
+// CHECK-NEXT: [[T0:%.*]] = load [[TEST29]]** [[SELF]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST29]]* [[T0]] to i8*
+// CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind, !clang.imprecise_release
+
+// Return.
+// CHECK-NEXT: [[T0:%.*]] = load i8** [[RET]]
+// CHECK-NEXT: ret i8* [[T0]]
+ self = [super initWithAllocator: allocator];
+ return self;
+}
+@end
+
+typedef struct Test30_helper Test30_helper;
+@interface Test30
+- (id) init;
+- (Test30_helper*) initHelper;
+@end
+@implementation Test30 {
+char *helper;
+}
+- (id) init {
+// CHECK: define internal i8* @"\01-[Test30 init]"([[TEST30:%.*]]* {{%.*}},
+// CHECK: [[RET:%.*]] = alloca i8*
+// CHECK-NEXT: [[SELF:%.*]] = alloca [[TEST30]]*
+// CHECK-NEXT: alloca i8*
+// CHECK-NEXT: alloca i32
+// CHECK-NEXT: store [[TEST30]]* {{%.*}}, [[TEST30]]** [[SELF]]
+// CHECK-NEXT: store
+
+// Call.
+// CHECK-NEXT: [[T0:%.*]] = load [[TEST30]]** [[SELF]]
+// CHECK-NEXT: [[T1:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST30]]* [[T0]] to i8*
+// CHECK-NEXT: [[CALL:%.*]] = call [[TEST30_HELPER:%.*]]* bitcast {{.*}} @objc_msgSend {{.*}}(i8* [[T2]], i8* [[T1]])
+
+// Assignment.
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[TEST30_HELPER]]* [[CALL]] to i8*
+// CHECK-NEXT: [[T1:%.*]] = load [[TEST30]]** [[SELF]]
+// CHECK-NEXT: [[IVAR:%.*]] = load i64* @"OBJC_IVAR_$_Test30.helper"
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST30]]* [[T1]] to i8*
+// CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds i8* [[T2]], i64 [[IVAR]]
+// CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to i8**
+// CHECK-NEXT#: [[T5:%.*]] = load i8** [[T4]]
+// CHECK-NEXT#: [[T6:%.*]] = call i8* @objc_retain(i8* [[T0]])
+// CHECK-NEXT#: call void @objc_release(i8* [[T5]])
+// CHECK-NEXT: store i8* [[T0]], i8** [[T4]]
+
+// Return.
+// CHECK-NEXT: [[T0:%.*]] = load [[TEST30]]** [[SELF]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST30]]* [[T0]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]])
+// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]]
+// CHECK-NEXT: [[T2:%.*]] = bitcast
+// CHECK-NEXT: store i8* [[T2]], i8** [[RET]]
+// CHECK-NEXT: store i32 1
+
+// Cleanup.
+// CHECK-NEXT: [[T0:%.*]] = load [[TEST30]]** [[SELF]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST30]]* [[T0]] to i8*
+// CHECK-NEXT: call void @objc_release(i8* [[T1]])
+
+// Epilogue.
+// CHECK-NEXT: [[T0:%.*]] = load i8** [[RET]]
+// CHECK-NEXT: ret i8* [[T0]]
+ self->helper = [self initHelper];
+ return self;
+}
+- (Test30_helper*) initHelper {
+// CHECK: define internal [[TEST30_HELPER]]* @"\01-[Test30 initHelper]"(
+// CHECK: alloca
+// CHECK-NEXT: alloca
+// CHECK-NEXT: store
+// CHECK-NEXT: store
+// CHECK-NEXT: ret [[TEST30_HELPER]]* null
+ return 0;
+}
+
+@end
+
+void test31(id x) {
+// CHECK: define void @test31(
+// CHECK: [[X:%.*]] = alloca i8*,
+// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
+// CHECK-NEXT: [[PARM:%.*]] = call i8* @objc_retain(i8* {{%.*}})
+// CHECK-NEXT: store i8* [[PARM]], i8** [[X]]
+// CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
+// CHECK-NEXT: [[T0:%.*]] = load i8** [[X]],
+// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]])
+// CHECK-NEXT: store i8* [[T1]], i8** [[SLOT]],
+// CHECK-NEXT: bitcast
+// CHECK-NEXT: call void @test31_helper(
+// CHECK-NEXT: [[T0:%.*]] = load i8** [[SLOT]]
+// CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind, !clang.imprecise_release
+// CHECK-NEXT: [[T0:%.*]] = load i8** [[X]]
+// CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind, !clang.imprecise_release
+// CHECK-NEXT: ret void
+ extern void test31_helper(id (^)(void));
+ test31_helper(^{ return x; });
+}
+
+__attribute__((ns_returns_retained)) id test32(void) {
+// CHECK: define i8* @test32()
+// CHECK: [[CALL:%.*]] = call i8* @test32_helper()
+// CHECK-NEXT: [[T0:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[CALL]])
+// CHECK-NEXT: ret i8* [[T0]]
+ extern id test32_helper(void);
+ return test32_helper();
+}
+
+@class Test33_a;
+@interface Test33
+- (void) give: (Test33_a **) x;
+- (void) take: (Test33_a **) x;
+- (void) giveStrong: (out __strong Test33_a **) x;
+- (void) takeStrong: (inout __strong Test33_a **) x;
+- (void) giveOut: (out Test33_a **) x;
+@end
+void test33(Test33 *ptr) {
+ Test33_a *a;
+ [ptr give: &a];
+ [ptr take: &a];
+ [ptr giveStrong: &a];
+ [ptr takeStrong: &a];
+ [ptr giveOut: &a];
+
+ // CHECK: define void @test33([[TEST33:%.*]]*
+ // CHECK: [[PTR:%.*]] = alloca [[TEST33]]*
+ // CHECK-NEXT: [[A:%.*]] = alloca [[A_T:%.*]]*
+ // CHECK-NEXT: [[TEMP0:%.*]] = alloca [[A_T]]*
+ // CHECK-NEXT: [[TEMP1:%.*]] = alloca [[A_T]]*
+ // CHECK-NEXT: [[TEMP2:%.*]] = alloca [[A_T]]*
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: objc_retain
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: store
+ // CHECK-NEXT: store [[A_T]]* null, [[A_T]]** [[A]]
+
+ // CHECK-NEXT: load [[TEST33]]** [[PTR]]
+ // CHECK-NEXT: [[T0:%.*]] = load [[A_T]]** [[A]]
+ // CHECK-NEXT: store [[A_T]]* [[T0]], [[A_T]]** [[TEMP0]]
+ // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: objc_msgSend{{.*}}, [[A_T]]** [[TEMP0]])
+ // CHECK-NEXT: [[T0:%.*]] = load [[A_T]]** [[TEMP0]]
+ // CHECK-NEXT: [[T1:%.*]] = bitcast [[A_T]]* [[T0]] to i8*
+ // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]])
+ // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[A_T]]*
+ // CHECK-NEXT: [[T4:%.*]] = load [[A_T]]** [[A]]
+ // CHECK-NEXT: store [[A_T]]* [[T3]], [[A_T]]** [[A]]
+ // CHECK-NEXT: [[T5:%.*]] = bitcast [[A_T]]* [[T4]] to i8*
+ // CHECK-NEXT: call void @objc_release(i8* [[T5]])
+
+ // CHECK-NEXT: load [[TEST33]]** [[PTR]]
+ // CHECK-NEXT: [[T0:%.*]] = load [[A_T]]** [[A]]
+ // CHECK-NEXT: store [[A_T]]* [[T0]], [[A_T]]** [[TEMP1]]
+ // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: objc_msgSend{{.*}}, [[A_T]]** [[TEMP1]])
+ // CHECK-NEXT: [[T0:%.*]] = load [[A_T]]** [[TEMP1]]
+ // CHECK-NEXT: [[T1:%.*]] = bitcast [[A_T]]* [[T0]] to i8*
+ // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]])
+ // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[A_T]]*
+ // CHECK-NEXT: [[T4:%.*]] = load [[A_T]]** [[A]]
+ // CHECK-NEXT: store [[A_T]]* [[T3]], [[A_T]]** [[A]]
+ // CHECK-NEXT: [[T5:%.*]] = bitcast [[A_T]]* [[T4]] to i8*
+ // CHECK-NEXT: call void @objc_release(i8* [[T5]])
+
+ // CHECK-NEXT: load [[TEST33]]** [[PTR]]
+ // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: objc_msgSend{{.*}}, [[A_T]]** [[A]])
+
+ // CHECK-NEXT: load [[TEST33]]** [[PTR]]
+ // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: objc_msgSend{{.*}}, [[A_T]]** [[A]])
+
+ // 'out'
+ // CHECK-NEXT: load [[TEST33]]** [[PTR]]
+ // CHECK-NEXT: store [[A_T]]* null, [[A_T]]** [[TEMP2]]
+ // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: objc_msgSend{{.*}}, [[A_T]]** [[TEMP2]])
+ // CHECK-NEXT: [[T0:%.*]] = load [[A_T]]** [[TEMP2]]
+ // CHECK-NEXT: [[T1:%.*]] = bitcast [[A_T]]* [[T0]] to i8*
+ // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]])
+ // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[A_T]]*
+ // CHECK-NEXT: [[T4:%.*]] = load [[A_T]]** [[A]]
+ // CHECK-NEXT: store [[A_T]]* [[T3]], [[A_T]]** [[A]]
+ // CHECK-NEXT: [[T5:%.*]] = bitcast [[A_T]]* [[T4]] to i8*
+ // CHECK-NEXT: call void @objc_release(i8* [[T5]])
+
+ // CHECK-NEXT: load
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: objc_release
+ // CHECK-NEXT: load
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: objc_release
+ // CHECK-NEXT: ret void
+}
+
+void test34(int cond) {
+ __strong id strong;
+ __weak id weak;
+ extern void test34_sink(id *);
+ test34_sink(cond ? &strong : 0);
+ test34_sink(cond ? &weak : 0);
+
+ // CHECK: define void @test34(
+ // CHECK: [[COND:%.*]] = alloca i32
+ // CHECK-NEXT: [[STRONG:%.*]] = alloca i8*
+ // CHECK-NEXT: [[WEAK:%.*]] = alloca i8*
+ // CHECK-NEXT: [[TEMP1:%.*]] = alloca i8*
+ // CHECK-NEXT: [[TEMP2:%.*]] = alloca i8*
+ // CHECK-NEXT: store i32
+ // CHECK-NEXT: store i8* null, i8** [[STRONG]]
+ // CHECK-NEXT: call i8* @objc_initWeak(i8** [[WEAK]], i8* null)
+
+ // CHECK-NEXT: [[T0:%.*]] = load i32* [[COND]]
+ // CHECK-NEXT: [[T1:%.*]] = icmp ne i32 [[T0]], 0
+ // CHECK: [[ARG:%.*]] = phi i8**
+ // CHECK-NEXT: [[T0:%.*]] = icmp eq i8** [[ARG]], null
+ // CHECK-NEXT: [[T1:%.*]] = select i1 [[T0]], i8** null, i8** [[TEMP1]]
+ // CHECK-NEXT: br i1 [[T0]],
+ // CHECK: [[T0:%.*]] = load i8** [[ARG]]
+ // CHECK-NEXT: store i8* [[T0]], i8** [[TEMP1]]
+ // CHECK-NEXT: br label
+ // CHECK: call void @test34_sink(i8** [[T1]])
+ // CHECK-NEXT: [[T0:%.*]] = icmp eq i8** [[ARG]], null
+ // CHECK-NEXT: br i1 [[T0]],
+ // CHECK: [[T0:%.*]] = load i8** [[TEMP1]]
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]])
+ // CHECK-NEXT: [[T2:%.*]] = load i8** [[ARG]]
+ // CHECK-NEXT: store i8* [[T1]], i8** [[ARG]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T2]])
+ // CHECK-NEXT: br label
+
+ // CHECK: [[T0:%.*]] = load i32* [[COND]]
+ // CHECK-NEXT: [[T1:%.*]] = icmp ne i32 [[T0]], 0
+ // CHECK: [[ARG:%.*]] = phi i8**
+ // CHECK-NEXT: [[T0:%.*]] = icmp eq i8** [[ARG]], null
+ // CHECK-NEXT: [[T1:%.*]] = select i1 [[T0]], i8** null, i8** [[TEMP2]]
+ // CHECK-NEXT: br i1 [[T0]],
+ // CHECK: [[T0:%.*]] = call i8* @objc_loadWeak(i8** [[ARG]])
+ // CHECK-NEXT: store i8* [[T0]], i8** [[TEMP2]]
+ // CHECK-NEXT: br label
+ // CHECK: call void @test34_sink(i8** [[T1]])
+ // CHECK-NEXT: [[T0:%.*]] = icmp eq i8** [[ARG]], null
+ // CHECK-NEXT: br i1 [[T0]],
+ // CHECK: [[T0:%.*]] = load i8** [[TEMP2]]
+ // CHECK-NEXT: call i8* @objc_storeWeak(i8** [[ARG]], i8* [[T0]])
+ // CHECK-NEXT: br label
+
+ // CHECK: call void @objc_destroyWeak(i8** [[WEAK]])
+ // CHECK: ret void
+}
+
+void test35(void (^sink)(id*)) {
+ __strong id strong;
+ sink(&strong);
+
+ // CHECK: define void @test35(
+ // CHECK: [[SINK:%.*]] = alloca void (i8**)*
+ // CHECK-NEXT: [[STRONG:%.*]] = alloca i8*
+ // CHECK-NEXT: [[TEMP:%.*]] = alloca i8*
+ // CHECK-NEXT: bitcast void (i8**)* {{%.*}} to i8*
+ // CHECK-NEXT: call i8* @objc_retain(
+ // CHECK-NEXT: bitcast i8*
+ // CHECK-NEXT: store void (i8**)* {{%.*}}, void (i8**)** [[SINK]]
+ // CHECK-NEXT: store i8* null, i8** [[STRONG]]
+
+ // CHECK-NEXT: load void (i8**)** [[SINK]]
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: getelementptr
+ // CHECK-NEXT: [[BLOCK:%.*]] = bitcast
+ // CHECK-NEXT: [[T0:%.*]] = load i8** [[STRONG]]
+ // CHECK-NEXT: store i8* [[T0]], i8** [[TEMP1]]
+ // CHECK-NEXT: [[F0:%.*]] = load i8**
+ // CHECK-NEXT: [[F1:%.*]] = bitcast i8* [[F0]] to void (i8*, i8**)*
+ // CHECK-NEXT: call void [[F1]](i8* [[BLOCK]], i8** [[TEMP1]])
+ // CHECK-NEXT: [[T0:%.*]] = load i8** [[TEMP1]]
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]])
+ // CHECK-NEXT: [[T2:%.*]] = load i8** [[STRONG]]
+ // CHECK-NEXT: store i8* [[T1]], i8** [[STRONG]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T2]])
+
+ // CHECK-NEXT: [[T0:%.*]] = load i8** [[STRONG]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T0]])
+
+ // CHECK-NEXT: load void (i8**)** [[SINK]]
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: call void @objc_release
+ // CHECK-NEXT: ret void
+
+}
+
+// CHECK: define void @test36
+void test36(id x) {
+ // CHECK: [[X:%.*]] = alloca i8*
+
+ // CHECK: call i8* @objc_retain
+ // CHECK: call i8* @objc_retain
+ // CHECK: call i8* @objc_retain
+ id array[3] = { @"A", x, @"y" };
+
+ // CHECK: [[T0:%.*]] = load i8** [[X]]
+ // CHECK-NEXT: store i8* null, i8** [[X]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T0]])
+ x = 0;
+
+ // CHECK: br label
+ // CHECK: call void @objc_release
+ // CHECK: br i1
+
+ // CHECK: call void @objc_release
+ // CHECK-NEXT: ret void
+}
+
+@class Test37;
+void test37(void) {
+ extern void test37_helper(id *);
+ Test37 *var;
+ test37_helper(&var);
+
+ // CHECK: define void @test37()
+ // CHECK: [[VAR:%.*]] = alloca [[TEST37:%.*]]*,
+ // CHECK-NEXT: [[TEMP:%.*]] = alloca i8*
+ // CHECK-NEXT: store [[TEST37]]* null, [[TEST37]]** [[VAR]]
+
+ // CHECK-NEXT: [[T0:%.*]] = load [[TEST37]]** [[VAR]]
+ // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST37]]* [[T0]] to i8*
+ // CHECK-NEXT: store i8* [[T1]], i8** [[TEMP]]
+ // CHECK-NEXT: call void @test37_helper(i8** [[TEMP]])
+ // CHECK-NEXT: [[T0:%.*]] = load i8** [[TEMP]]
+ // CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[TEST37]]*
+ // CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST37]]* [[T1]] to i8*
+ // CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]])
+ // CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to [[TEST37]]*
+ // CHECK-NEXT: [[T5:%.*]] = load [[TEST37]]** [[VAR]]
+ // CHECK-NEXT: store [[TEST37]]* [[T4]], [[TEST37]]** [[VAR]]
+ // CHECK-NEXT: [[T6:%.*]] = bitcast [[TEST37]]* [[T5]] to i8*
+ // CHECK-NEXT: call void @objc_release(i8* [[T6]])
+
+ // CHECK-NEXT: [[T0:%.*]] = load [[TEST37]]** [[VAR]]
+ // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST37]]* [[T0]] to i8*
+ // CHECK-NEXT: call void @objc_release(i8* [[T1]])
+ // CHECK-NEXT: ret void
+}
+
+void test38(void) {
+ id test38_source(void);
+ void test38_helper(void (^)(void));
+ __block id var = test38_source();
+ test38_helper(^{ var = 0; });
+
+ // CHECK: define void @test38()
+ // CHECK: [[VAR:%.*]] = alloca [[BYREF_T:%.*]],
+ // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
+ // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 2
+ // 0x02000000 - has copy/dispose helpers
+ // CHECK-NEXT: store i32 33554432, i32* [[T0]]
+ // CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6
+ // CHECK-NEXT: [[T0:%.*]] = call i8* @test38_source()
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
+ // CHECK-NEXT: store i8* [[T1]], i8** [[SLOT]]
+ // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6
+ // 0x42000000 - has signature, copy/dispose helpers
+ // CHECK: store i32 1107296256,
+ // CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8*
+ // CHECK-NEXT: store i8* [[T0]], i8**
+ // CHECK: call void @test38_helper(
+ // CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8*
+ // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8)
+ // CHECK-NEXT: [[T0:%.*]] = load i8** [[SLOT]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T0]])
+ // CHECK-NEXT: ret void
+
+ // CHECK: define internal void @__Block_byref_object_copy_
+ // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
+ // CHECK-NEXT: load i8**
+ // CHECK-NEXT: bitcast i8* {{%.*}} to [[BYREF_T]]*
+ // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
+ // CHECK-NEXT: [[T2:%.*]] = load i8** [[T1]]
+ // CHECK-NEXT: store i8* [[T2]], i8** [[T0]]
+ // CHECK-NEXT: store i8* null, i8** [[T1]]
+
+ // CHECK: define internal void @__Block_byref_object_dispose_
+ // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
+ // CHECK-NEXT: [[T1:%.*]] = load i8** [[T0]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T1]])
+
+ // CHECK: define internal void @__test38_block_invoke_
+ // CHECK: [[SLOT:%.*]] = getelementptr inbounds {{.*}}, i32 0, i32 6
+ // CHECK-NEXT: [[T0:%.*]] = load i8** [[SLOT]], align 8
+ // CHECK-NEXT: store i8* null, i8** [[SLOT]],
+ // CHECK-NEXT: call void @objc_release(i8* [[T0]])
+ // CHECK-NEXT: ret void
+
+ // CHECK: define internal void @__copy_helper_block_
+ // CHECK: call void @_Block_object_assign(i8* {{%.*}}, i8* {{%.*}}, i32 8)
+
+ // CHECK: define internal void @__destroy_helper_block_
+ // CHECK: call void @_Block_object_dispose(i8* {{%.*}}, i32 8)
+}
+
+void test39(void) {
+ extern id test39_source(void);
+ void test39_helper(void (^)(void));
+ __unsafe_unretained id var = test39_source();
+ test39_helper(^{ (void) var; });
+
+ // CHECK: define void @test39()
+ // CHECK: [[VAR:%.*]] = alloca i8*
+ // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
+ // CHECK: [[T0:%.*]] = call i8* @test39_source()
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
+ // CHECK-NEXT: store i8* [[T1]], i8** [[VAR]],
+ // CHECK-NEXT: call void @objc_release(i8* [[T1]])
+ // 0x40000000 - has signature but no copy/dispose
+ // CHECK: store i32 1073741824, i32*
+ // CHECK: [[CAPTURE:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
+ // CHECK-NEXT: [[T0:%.*]] = load i8** [[VAR]]
+ // CHECK-NEXT: store i8* [[T0]], i8** [[CAPTURE]]
+ // CHECK-NEXT: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to
+ // CHECK: call void @test39_helper
+ // CHECK-NEXT: ret void
+}
+
+void test40(void) {
+ id test40_source(void);
+ void test40_helper(void (^)(void));
+ __block __weak id var = test40_source();
+ test40_helper(^{ var = 0; });
+
+ // CHECK: define void @test40()
+ // CHECK: [[VAR:%.*]] = alloca [[BYREF_T:%.*]],
+ // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
+ // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 2
+ // 0x02000000 - has copy/dispose helpers
+ // CHECK-NEXT: store i32 33554432, i32* [[T0]]
+ // CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6
+ // CHECK-NEXT: [[T0:%.*]] = call i8* @test40_source()
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
+ // CHECK-NEXT: call i8* @objc_initWeak(i8** [[SLOT]], i8* [[T1]])
+ // CHECK-NEXT: call void @objc_release(i8* [[T1]])
+ // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6
+ // 0x42000000 - has signature, copy/dispose helpers
+ // CHECK: store i32 1107296256,
+ // CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8*
+ // CHECK-NEXT: store i8* [[T0]], i8**
+ // CHECK: call void @test40_helper(
+ // CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8*
+ // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8)
+ // CHECK-NEXT: call void @objc_destroyWeak(i8** [[SLOT]])
+ // CHECK-NEXT: ret void
+
+ // CHECK: define internal void @__Block_byref_object_copy_
+ // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
+ // CHECK-NEXT: load i8**
+ // CHECK-NEXT: bitcast i8* {{%.*}} to [[BYREF_T]]*
+ // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
+ // CHECK-NEXT: call void @objc_moveWeak(i8** [[T0]], i8** [[T1]])
+
+ // CHECK: define internal void @__Block_byref_object_dispose_
+ // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
+ // CHECK-NEXT: call void @objc_destroyWeak(i8** [[T0]])
+
+ // CHECK: define internal void @__test40_block_invoke_
+ // CHECK: [[SLOT:%.*]] = getelementptr inbounds {{.*}}, i32 0, i32 6
+ // CHECK-NEXT: call i8* @objc_storeWeak(i8** [[SLOT]], i8* null)
+ // CHECK-NEXT: ret void
+
+ // CHECK: define internal void @__copy_helper_block_
+ // 0x8 - FIELD_IS_BYREF (no FIELD_IS_WEAK because clang in control)
+ // CHECK: call void @_Block_object_assign(i8* {{%.*}}, i8* {{%.*}}, i32 8)
+
+ // CHECK: define internal void @__destroy_helper_block_
+ // 0x8 - FIELD_IS_BYREF (no FIELD_IS_WEAK because clang in control)
+ // CHECK: call void @_Block_object_dispose(i8* {{%.*}}, i32 8)
+}
+
+void test41(void) {
+ id test41_source(void);
+ void test41_helper(void (^)(void));
+ void test41_consume(id);
+ __weak id var = test41_source();
+ test41_helper(^{ test41_consume(var); });
+
+ // CHECK: define void @test41()
+ // CHECK: [[VAR:%.*]] = alloca i8*,
+ // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
+ // CHECK: [[T0:%.*]] = call i8* @test41_source()
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
+ // CHECK-NEXT: call i8* @objc_initWeak(i8** [[VAR]], i8* [[T1]])
+ // CHECK-NEXT: call void @objc_release(i8* [[T1]])
+ // 0x42000000 - has signature, copy/dispose helpers
+ // CHECK: store i32 1107296256,
+ // CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
+ // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_loadWeak(i8** [[VAR]])
+ // CHECK-NEXT: call i8* @objc_initWeak(i8** [[SLOT]], i8* [[T0]])
+ // CHECK: call void @test41_helper(
+ // CHECK-NEXT: call void @objc_destroyWeak(i8** [[SLOT]])
+ // CHECK-NEXT: call void @objc_destroyWeak(i8** [[VAR]])
+ // CHECK-NEXT: ret void
+
+ // CHECK: define internal void @__test41_block_invoke_
+ // CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]]* {{%.*}}, i32 0, i32 5
+ // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_loadWeak(i8** [[SLOT]])
+ // CHECK-NEXT: call void @test41_consume(i8* [[T0]])
+ // CHECK-NEXT: ret void
+
+ // CHECK: define internal void @__copy_helper_block_
+ // CHECK: getelementptr
+ // CHECK-NEXT: getelementptr
+ // CHECK-NEXT: call void @objc_copyWeak(
+
+ // CHECK: define internal void @__destroy_helper_block_
+ // CHECK: getelementptr
+ // CHECK-NEXT: call void @objc_destroyWeak(
+}
+
+@interface Test42 @end
+@implementation Test42
+- (void) test {
+// CHECK: define internal void @"\01-[Test42 test]"
+// CHECK: [[SELF:%.*]] = alloca [[TEST42:%.*]]*,
+// CHECK-NEXT: alloca i8*
+// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
+// CHECK: store
+// CHECK-NEXT: store
+// CHECK: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
+// CHECK-NEXT: [[T1:%.*]] = load [[TEST42]]** [[SELF]],
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST42]]* [[T1]] to i8*
+// CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]])
+// CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to [[TEST42]]*
+// CHECK-NEXT: store [[TEST42]]* [[T4]], [[TEST42]]** [[T0]]
+// CHECK-NEXT: bitcast [[BLOCK_T]]* [[BLOCK]] to
+// CHECK: call void @test42_helper(
+// CHECK-NEXT: [[T1:%.*]] = load [[TEST42]]** [[T0]]
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST42]]* [[T1]] to i8*
+// CHECK-NEXT: call void @objc_release(i8* [[T2]])
+// CHECK-NEXT: ret void
+
+ extern void test42_helper(void (^)(void));
+ test42_helper(^{ (void) self; });
+}
+@end
+
+@interface Test43 @end
+@implementation Test43
+- (id) test __attribute__((ns_returns_retained)) {
+ extern id test43_produce(void);
+ return test43_produce();
+ // CHECK: call i8* @test43_produce()
+ // CHECK-NEXT: call i8* @objc_retainAutoreleasedReturnValue(
+ // CHECK-NEXT: ret
+}
+@end
+
+id test44(void) {
+ typedef id __attribute__((ns_returns_retained)) blocktype(void);
+ extern test44_consume_block(blocktype^);
+ return ^blocktype {
+ extern id test44_produce(void);
+ return test44_produce();
+ }();
+
+// CHECK: define i8* @test44(
+// CHECK: load i8** getelementptr
+// CHECK-NEXT: bitcast i8*
+// CHECK-NEXT: call i8*
+// CHECK-NEXT: call i8* @objc_autoreleaseReturnValue
+// CHECK-NEXT: ret i8*
+
+// CHECK: call i8* @test44_produce()
+// CHECK-NEXT: call i8* @objc_retain
+// CHECK-NEXT: ret i8*
+}
+
+@interface Test45
+@property (retain) id x;
+@end
+@implementation Test45
+@synthesize x;
+@end
+// CHECK: define internal i8* @"\01-[Test45 x]"(
+// CHECK: [[CALL:%.*]] = call i8* @objc_getProperty(
+// CHECK-NEXT: ret i8* [[CALL]]
+
+// rdar://problem/9315552
+void test46(__weak id *wp, __weak volatile id *wvp) {
+ extern id test46_helper(void);
+
+ // TODO: this is sub-optimal, we should retain at the actual call site.
+
+ // CHECK: [[T0:%.*]] = call i8* @test46_helper()
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
+ // CHECK-NEXT: [[T2:%.*]] = load i8*** {{%.*}}, align 8
+ // CHECK-NEXT: [[T3:%.*]] = call i8* @objc_storeWeak(i8** [[T2]], i8* [[T1]])
+ // CHECK-NEXT: [[T4:%.*]] = call i8* @objc_retain(i8* [[T3]])
+ // CHECK-NEXT: store i8* [[T4]], i8**
+ // CHECK-NEXT: call void @objc_release(i8* [[T1]])
+ id x = *wp = test46_helper();
+
+ // CHECK: [[T0:%.*]] = call i8* @test46_helper()
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
+ // CHECK-NEXT: [[T2:%.*]] = load i8*** {{%.*}}, align 8
+ // CHECK-NEXT: [[T3:%.*]] = call i8* @objc_storeWeak(i8** [[T2]], i8* [[T1]])
+ // CHECK-NEXT: [[T4:%.*]] = call i8* @objc_retain(i8* [[T3]])
+ // CHECK-NEXT: store i8* [[T4]], i8**
+ // CHECK-NEXT: call void @objc_release(i8* [[T1]])
+ id y = *wvp = test46_helper();
+}
+
+// rdar://problem/9378887
+void test47(void) {
+ extern id test47_helper(void);
+ id x = x = test47_helper();
+
+ // CHECK: define void @test47()
+ // CHECK: [[X:%.*]] = alloca i8*
+ // CHECK-NEXT: store i8* null, i8** [[X]]
+ // CHECK-NEXT: [[CALL:%.*]] = call i8* @test47_helper()
+ // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[CALL]])
+ // CHECK-NEXT: [[T1:%.*]] = load i8** [[X]]
+ // CHECK-NEXT: store i8* [[T0]], i8** [[X]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T1]])
+ // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T0]])
+ // CHECK-NEXT: [[T3:%.*]] = load i8** [[X]]
+ // CHECK-NEXT: store i8* [[T2]], i8** [[X]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T3]])
+ // CHECK-NEXT: [[T4:%.*]] = load i8** [[X]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T4]])
+ // CHECK-NEXT: ret void
+}
+
+void test48(void) {
+ extern id test48_helper(void);
+ __weak id x = x = test48_helper();
+ // CHECK: define void @test48()
+ // CHECK: [[X:%.*]] = alloca i8*
+ // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_initWeak(i8** [[X]], i8* null)
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @test48_helper()
+ // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
+ // CHECK-NEXT: [[T3:%.*]] = call i8* @objc_storeWeak(i8** [[X]], i8* [[T2]])
+ // CHECK-NEXT: [[T4:%.*]] = call i8* @objc_storeWeak(i8** [[X]], i8* [[T3]])
+ // CHECK-NEXT: call void @objc_release(i8* [[T2]])
+ // CHECK-NEXT: call void @objc_destroyWeak(i8** [[X]])
+ // CHECK-NEXT: ret void
+}
+
+void test49(void) {
+ extern id test49_helper(void);
+ __autoreleasing id x = x = test49_helper();
+ // CHECK: define void @test49()
+ // CHECK: [[X:%.*]] = alloca i8*
+ // CHECK-NEXT: store i8* null, i8** [[X]]
+ // CHECK-NEXT: [[CALL:%.*]] = call i8* @test49_helper()
+ // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[CALL]])
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_autorelease(i8* [[T0]])
+ // CHECK-NEXT: store i8* [[T2]], i8** [[X]]
+ // CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retainAutorelease(i8* [[T1]])
+ // CHECK-NEXT: store i8* [[T3]], i8** [[X]]
+ // CHECK-NEXT: ret void
+}
+
+// rdar://9380136
+id x();
+void test50(id y) {
+ ({x();});
+// CHECK: [[T0:%.*]] = call i8* @objc_retain
+// CHECK: call void @objc_release
+}
+
+
+// rdar://9400762
+struct CGPoint {
+ float x;
+ float y;
+};
+typedef struct CGPoint CGPoint;
+
+@interface Foo
+@property (assign) CGPoint point;
+@end
+
+@implementation Foo
+@synthesize point;
+@end
+
+// rdar://problem/9400398
+id test52(void) {
+ id test52_helper(int) __attribute__((ns_returns_retained));
+ return ({ int x = 5; test52_helper(x); });
+
+// CHECK: define i8* @test52()
+// CHECK: [[X:%.*]] = alloca i32
+// CHECK-NEXT: store i32 5, i32* [[X]],
+// CHECK-NEXT: [[T0:%.*]] = load i32* [[X]],
+// CHECK-NEXT: [[T1:%.*]] = call i8* @test52_helper(i32 [[T0]])
+// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_autoreleaseReturnValue(i8* [[T1]])
+// CHECK-NEXT: ret i8* [[T2]]
+}
+
+// rdar://problem/9400644
+void test53(void) {
+ id test53_helper(void);
+ id x = ({ id y = test53_helper(); y; });
+ (void) x;
+// CHECK: define void @test53()
+// CHECK: [[X:%.*]] = alloca i8*,
+// CHECK-NEXT: [[Y:%.*]] = alloca i8*,
+// CHECK-NEXT: [[T0:%.*]] = call i8* @test53_helper()
+// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
+// CHECK-NEXT: store i8* [[T1]], i8** [[Y]],
+// CHECK-NEXT: [[T0:%.*]] = load i8** [[Y]],
+// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]])
+// CHECK-NEXT: [[T2:%.*]] = load i8** [[Y]]
+// CHECK-NEXT: call void @objc_release(i8* [[T2]])
+// CHECK-NEXT: store i8* [[T1]], i8** [[X]],
+// CHECK-NEXT: load i8** [[X]],
+// CHECK-NEXT: [[T0:%.*]] = load i8** [[X]]
+// CHECK-NEXT: call void @objc_release(i8* [[T0]])
+// CHECK-NEXT: ret void
+}
+
+// <rdar://problem/9758798>
+// CHECK: define void @test54(i32 %first, ...)
+void test54(int first, ...) {
+ __builtin_va_list arglist;
+ // CHECK: call void @llvm.va_start
+ __builtin_va_start(arglist, first);
+ // CHECK: call i8* @objc_retain
+ id obj = __builtin_va_arg(arglist, id);
+ // CHECK: call void @llvm.va_end
+ __builtin_va_end(arglist);
+ // CHECK: call void @objc_release
+ // CHECK: ret void
+}
+
+// PR10228
+@interface Test55Base @end
+@interface Test55 : Test55Base @end
+@implementation Test55 (Category)
+- (void) dealloc {}
+@end
+// CHECK: define internal void @"\01-[Test55(Category) dealloc]"(
+// CHECK-NOT: ret
+// CHECK: call void bitcast (i8* ({{%.*}}*, i8*, ...)* @objc_msgSendSuper2 to void ({{%.*}}*, i8*)*)(
diff --git a/test/CodeGenObjC/autorelease.m b/test/CodeGenObjC/autorelease.m
new file mode 100644
index 000000000000..7bf40f11ffd1
--- /dev/null
+++ b/test/CodeGenObjC/autorelease.m
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-arc -fobjc-nonfragile-abi -fobjc-runtime-has-arc -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -emit-llvm -fobjc-nonfragile-abi -fobjc-runtime-has-arc -o - %s | FileCheck %s
+// rdar://8881826
+// rdar://9412038
+
+@interface I
+{
+ id ivar;
+}
+- (id) Meth;
++ (id) MyAlloc;;
+@end
+
+@implementation I
+- (id) Meth {
+ @autoreleasepool {
+ id p = [I MyAlloc];
+ if (!p)
+ return ivar;
+ }
+ return 0;
+}
++ (id) MyAlloc {
+ return 0;
+}
+@end
+
+// CHECK: call i8* @objc_autoreleasePoolPush
+// CHECK: [[T:%.*]] = load i8** [[A:%.*]]
+// CHECK: call void @objc_autoreleasePoolPop
diff --git a/test/CodeGenObjC/block-6.m b/test/CodeGenObjC/block-6.m
index 3720a87b9e56..44c7a78e698e 100644
--- a/test/CodeGenObjC/block-6.m
+++ b/test/CodeGenObjC/block-6.m
@@ -2,10 +2,16 @@
// rdar://8893785
void MYFUNC() {
-// CHECK: [[T1:%.*]] = bitcast i8* ()*
-// CHECK-NEXT: [[FORWARDING:%.*]] = getelementptr inbounds [[N_T:%.*]]* [[N:%.*]], i32 0, i32 1
-// CHECK-NEXT: [[T0:%.*]] = load [[N_T]]** [[FORWARDING]]
-// CHECK-NEXT: [[OBSERVER:%.*]] = getelementptr inbounds [[N_T]]* [[T0]], i32 0, i32 6
+// CHECK: define void @MYFUNC()
+// CHECK: [[OBSERVER_SLOT:%.*]] = alloca [[OBSERVER_T:%.*]], align 8
+
+// CHECK: [[T0:%.*]] = getelementptr inbounds [[OBSERVER_T]]* [[OBSERVER_SLOT]], i32 0, i32 1
+// CHECK: store [[OBSERVER_T]]* [[OBSERVER_SLOT]], [[OBSERVER_T]]** [[T0]]
+
+// CHECK: [[T1:%.*]] = bitcast i8* ()*
+// CHECK: [[FORWARDING:%.*]] = getelementptr inbounds [[OBSERVER_T]]* [[OBSERVER_SLOT]], i32 0, i32 1
+// CHECK-NEXT: [[T0:%.*]] = load [[OBSERVER_T]]** [[FORWARDING]]
+// CHECK-NEXT: [[OBSERVER:%.*]] = getelementptr inbounds [[OBSERVER_T]]* [[T0]], i32 0, i32 6
// CHECK-NEXT: store i8* [[T1]], i8** [[OBSERVER]]
__block id observer = ^{ return observer; };
}
diff --git a/test/CodeGenObjC/blocks.m b/test/CodeGenObjC/blocks.m
index 151c16234214..47d47cca2e8c 100644
--- a/test/CodeGenObjC/blocks.m
+++ b/test/CodeGenObjC/blocks.m
@@ -46,7 +46,7 @@ void test2(Test2 *x) {
// CHECK: define void @test2(
// CHECK: [[X:%.*]] = alloca [[TEST2:%.*]]*,
// CHECK-NEXT: [[WEAKX:%.*]] = alloca [[WEAK_T:%.*]],
- // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:%.*]],
+ // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
// CHECK-NEXT: store [[TEST2]]*
// isa=1 for weak byrefs.
@@ -95,8 +95,8 @@ void test2(Test2 *x) {
// CHECK: [[BLOCK:%.*]] = bitcast i8* {{%.*}} to [[BLOCK_T]]*
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
// CHECK-NEXT: [[T1:%.*]] = load i8** [[T0]]
-// CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to [[WEAK_T]]*
-// CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds [[WEAK_T]]* [[T2]], i32 0, i32 1
-// CHECK-NEXT: [[T4:%.*]] = load [[WEAK_T]]** [[T3]]
-// CHECK-NEXT: [[WEAKX:%.*]] = getelementptr inbounds [[WEAK_T]]* [[T4]], i32 0, i32 6
+// CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to [[WEAK_T]]{{.*}}*
+// CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds [[WEAK_T]]{{.*}}* [[T2]], i32 0, i32 1
+// CHECK-NEXT: [[T4:%.*]] = load [[WEAK_T]]{{.*}}** [[T3]]
+// CHECK-NEXT: [[WEAKX:%.*]] = getelementptr inbounds [[WEAK_T]]{{.*}}* [[T4]], i32 0, i32 6
// CHECK-NEXT: [[T0:%.*]] = load [[TEST2]]** [[WEAKX]], align 4
diff --git a/test/CodeGenObjC/debug-info-foreach.m b/test/CodeGenObjC/debug-info-foreach.m
deleted file mode 100644
index 89b409c7169e..000000000000
--- a/test/CodeGenObjC/debug-info-foreach.m
+++ /dev/null
@@ -1,20 +0,0 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fobjc-default-synthesize-properties -emit-llvm -g %s -o %t
-// RUN: grep DW_TAG_lexical_block %t | count 5
-// rdar://8757124
-
-@class NSArray;
-
-int i;
-void f(NSArray *a) {
- id keys;
- for (id thisKey in keys) {
- int j = i;
- ++j;
- i = j;
- }
- for (id thisKey in keys) {
- int k = i;
- ++k;
- i = k;
- }
-}
diff --git a/test/CodeGenObjC/encode-test.m b/test/CodeGenObjC/encode-test.m
index ade0c618225f..f30fb26a1e65 100644
--- a/test/CodeGenObjC/encode-test.m
+++ b/test/CodeGenObjC/encode-test.m
@@ -161,3 +161,7 @@ struct f
// CHECK: @g10 = constant [14 x i8] c"{f=i[0{?=}]i}\00"
const char g10[] = @encode(struct f);
+
+// rdar://9622422
+// CHECK: @g11 = constant [2 x i8] c"v\00"
+const char g11[] = @encode(void);
diff --git a/test/CodeGenObjC/exceptions-nonfragile.m b/test/CodeGenObjC/exceptions-nonfragile.m
index 280b5d416ffa..2557aab25219 100644
--- a/test/CodeGenObjC/exceptions-nonfragile.m
+++ b/test/CodeGenObjC/exceptions-nonfragile.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -fexceptions -fobjc-exceptions -O2 -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -fexceptions -fobjc-exceptions -o - %s | FileCheck %s
// rdar://problem/8535238
// CHECK: declare void @objc_exception_rethrow()
@@ -15,3 +15,17 @@ void protos() {
void throwing() {
@throw(@"error!");
}
+
+// rdar://problem/9431547
+void die(void) __attribute__((nothrow, noreturn));
+void test2(void) {
+ @try {
+ die();
+ } @finally {
+ extern void test2_helper(void);
+ test2_helper();
+ }
+
+ // CHECK: define void @test2()
+ // CHECK-NOT: call void @test2_helper()
+}
diff --git a/test/CodeGenObjC/gc.m b/test/CodeGenObjC/gc.m
new file mode 100644
index 000000000000..93554e65b880
--- /dev/null
+++ b/test/CodeGenObjC/gc.m
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-gc -fobjc-nonfragile-abi -emit-llvm -o - %s | FileCheck %s
+
+void test0(void) {
+ extern id test0_helper(void);
+ __attribute__((objc_precise_lifetime)) id x = test0_helper();
+ test0_helper();
+ // CHECK: define void @test0()
+ // CHECK: [[T0:%.*]] = call i8* @test0_helper()
+ // CHECK-NEXT: store i8* [[T0]], i8** [[X:%.*]], align 8
+ // CHECK-NEXT: call i8* @test0_helper()
+ // CHECK-NEXT: [[T0:%.*]] = load i8** [[X]], align 8
+ // CHECK-NEXT: call void asm sideeffect "", "r"(i8* [[T0]]) nounwind
+ // CHECK-NEXT: ret void
+}
diff --git a/test/CodeGenObjC/mrr-autorelease.m b/test/CodeGenObjC/mrr-autorelease.m
new file mode 100644
index 000000000000..10f549fcec5e
--- /dev/null
+++ b/test/CodeGenObjC/mrr-autorelease.m
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
+// rdar://8881826
+// rdar://9423507
+
+@interface I
+{
+ id ivar;
+}
+- (id) Meth;
+@end
+
+@implementation I
+- (id) Meth {
+ @autoreleasepool {
+ }
+ return 0;
+}
+@end
+
+// CHECK-NOT: call i8* @objc_getClass
+// CHECK: call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
+// CHECK: call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
+// CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
diff --git a/test/CodeGenObjC/nonlazy-msgSend.m b/test/CodeGenObjC/nonlazy-msgSend.m
new file mode 100644
index 000000000000..3d7ba10dc5e8
--- /dev/null
+++ b/test/CodeGenObjC/nonlazy-msgSend.m
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -emit-llvm -o %t %s
+// RUN: grep -F 'declare i8* @objc_msgSend(i8*, i8*, ...) nonlazybind' %t
+
+void f0(id x) {
+ [x foo];
+}
diff --git a/test/CodeGenObjC/property-list-in-class.m b/test/CodeGenObjC/property-list-in-class.m
index a5d0dc851dc4..05210588ba9b 100644
--- a/test/CodeGenObjC/property-list-in-class.m
+++ b/test/CodeGenObjC/property-list-in-class.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -emit-llvm -o %t %s
-// RUN: grep -F 'l_OBJC_$_PROP_LIST_C2" = internal global %8 { i32 16, i32 3' %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -emit-llvm %s -o - | FileCheck %s
+// CHECK: l_OBJC_$_PROP_LIST_C2" = internal global { i32, i32, [3 x %struct._prop_t] } { i32 16, i32 3
@protocol P
@property int i;
diff --git a/test/CodeGenObjC/related-result-type.m b/test/CodeGenObjC/related-result-type.m
new file mode 100644
index 000000000000..ef38661f94c0
--- /dev/null
+++ b/test/CodeGenObjC/related-result-type.m
@@ -0,0 +1,54 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+
+@interface NSObject
++ (id)alloc;
+- (id)init;
+- (id)retain;
+@end
+
+@interface NSString : NSObject
+@end
+
+// CHECK: define void @test1()
+void test1() {
+ // CHECK: {{call.*@objc_msgSend}}
+ // CHECK: {{call.*@objc_msgSend}}
+ // CHECK: {{call.*@objc_msgSend}}
+ // CHECK: bitcast i8*
+ NSString *str1 = [[[NSString alloc] init] retain];
+}
+
+// CHECK: define void @test2()
+void test2() {
+ // CHECK: {{call.*@objc_msgSend}}
+ // CHECK: {{call.*@objc_msgSend}}
+ // CHECK: {{call.*@objc_msgSend}}
+ // CHECK: bitcast i8*
+ NSString *str1 = NSString.alloc.init.retain;
+}
+
+@interface Test2 : NSString
+- (id)init;
+@end
+
+@implementation Test2
+// CHECK: define internal i8* @"\01-[Test2 init]"
+- (id)init {
+ // CHECK: {{call.*@objc_msgSendSuper}}
+ // CHECK-NEXT: bitcast i8*
+ return [super init];
+}
+@end
+
+@interface Test3 : NSString
+- (id)init;
+@end
+
+@implementation Test3
+// CHECK: define internal i8* @"\01-[Test3 init]"
+- (id)init {
+ // CHECK: {{call.*@objc_msgSendSuper}}
+ // CHECK-NEXT: bitcast i8*
+ return [super init];
+}
+@end
diff --git a/test/CodeGenObjC/terminate.m b/test/CodeGenObjC/terminate.m
new file mode 100644
index 000000000000..f04eb6a92bb7
--- /dev/null
+++ b/test/CodeGenObjC/terminate.m
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fexceptions -fobjc-exceptions -fobjc-runtime-has-terminate -o - %s | FileCheck %s -check-prefix=CHECK-WITH
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fexceptions -fobjc-exceptions -o - %s | FileCheck %s -check-prefix=CHECK-WITHOUT
+
+void destroy(void**);
+
+// rdar://problem/9519113
+void test0(void) {
+ void test0_helper(void);
+ void *ptr __attribute__((cleanup(destroy)));
+ test0_helper();
+
+ // CHECK-WITH: define void @test0()
+ // CHECK-WITH: [[PTR:%.*]] = alloca i8*,
+ // CHECK-WITH: call void @destroy(i8** [[PTR]])
+ // CHECK-WITH-NEXT: ret void
+ // CHECK-WITH: invoke void @destroy(i8** [[PTR]])
+ // CHECK-WITH: call i8* @llvm.eh.exception()
+ // CHECK-WITH-NEXT: @llvm.eh.selector
+ // CHECK-WITH-NEXT: call void @objc_terminate()
+
+ // CHECK-WITHOUT: define void @test0()
+ // CHECK-WITHOUT: [[PTR:%.*]] = alloca i8*,
+ // CHECK-WITHOUT: call void @destroy(i8** [[PTR]])
+ // CHECK-WITHOUT-NEXT: ret void
+ // CHECK-WITHOUT: invoke void @destroy(i8** [[PTR]])
+ // CHECK-WITHOUT: call i8* @llvm.eh.exception()
+ // CHECK-WITHOUT-NEXT: @llvm.eh.selector
+ // CHECK-WITHOUT-NEXT: call void @abort()
+}
diff --git a/test/CodeGenObjC/variadic-sends.m b/test/CodeGenObjC/variadic-sends.m
index ea13823bc719..6b04b50ca152 100644
--- a/test/CodeGenObjC/variadic-sends.m
+++ b/test/CodeGenObjC/variadic-sends.m
@@ -28,13 +28,13 @@ void f2(A *a) {
@interface B : A @end
@implementation B : A
-(void) foo {
- // CHECK-X86-32: call void bitcast (i8* (%struct._objc_method_description*, i8*, ...)* @objc_msgSendSuper to void (%struct._objc_method_description*, i8*, i32)*)
- // CHECK-X86-64: call void bitcast (i8* (%struct._objc_method_description*, i8*, ...)* @objc_msgSendSuper to void (%struct._objc_method_description*, i8*, i32)*)
+ // CHECK-X86-32: call void bitcast (i8* (%struct._objc_super*, i8*, ...)* @objc_msgSendSuper to void (%struct._objc_super*, i8*, i32)*)
+ // CHECK-X86-64: call void bitcast (i8* (%struct._objc_super*, i8*, ...)* @objc_msgSendSuper to void (%struct._objc_super*, i8*, i32)*)
[super im1: 1];
}
-(void) bar {
- // CHECK-X86-32: call void (%struct._objc_method_description*, i8*, i32, i32, ...)* bitcast (i8* (%struct._objc_method_description*, i8*, ...)* @objc_msgSendSuper to void (%struct._objc_method_description*, i8*, i32, i32, ...)*)
- // CHECK-X86-64: call void (%struct._objc_method_description*, i8*, i32, i32, ...)* bitcast (i8* (%struct._objc_method_description*, i8*, ...)* @objc_msgSendSuper to void (%struct._objc_method_description*, i8*, i32, i32, ...)*)
+ // CHECK-X86-32: call void (%struct._objc_super*, i8*, i32, i32, ...)* bitcast (i8* (%struct._objc_super*, i8*, ...)* @objc_msgSendSuper to void (%struct._objc_super*, i8*, i32, i32, ...)*)
+ // CHECK-X86-64: call void (%struct._objc_super*, i8*, i32, i32, ...)* bitcast (i8* (%struct._objc_super*, i8*, ...)* @objc_msgSendSuper to void (%struct._objc_super*, i8*, i32, i32, ...)*)
[super im2: 1, 2];
}
diff --git a/test/CodeGenObjCXX/arc-globals.mm b/test/CodeGenObjCXX/arc-globals.mm
new file mode 100644
index 000000000000..7167dbc366d0
--- /dev/null
+++ b/test/CodeGenObjCXX/arc-globals.mm
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -fblocks -fobjc-arc -O2 -disable-llvm-optzns -o - %s | FileCheck %s
+
+// Test that we're properly retaining lifetime-qualified pointers
+// initialized statically and wrapping up those initialization in an
+// autorelease pool.
+id getObject();
+
+// CHECK: define internal void @__cxx_global_var_init
+// CHECK: call i8* @_Z9getObjectv
+// CHECK-NEXT: call i8* @objc_retainAutoreleasedReturnValue
+// CHECK-NEXT: {{store i8*.*@global_obj}}
+// CHECK-NEXT: ret void
+id global_obj = getObject();
+
+// CHECK: define internal void @__cxx_global_var_init
+// CHECK: call i8* @_Z9getObjectv
+// CHECK-NEXT: call i8* @objc_retainAutoreleasedReturnValue
+// CHECK-NEXT: {{store i8*.*@global_obj2}}
+// CHECK-NEXT: ret void
+id global_obj2 = getObject();
+
+// CHECK: define internal void @_GLOBAL__I_a
+// CHECK: call i8* @objc_autoreleasePoolPush()
+// CHECK-NEXT: call void @__cxx_global_var_init
+// CHECK-NEXT: call void @__cxx_global_var_init1
+// CHECK-NEXT: call void @objc_autoreleasePoolPop(
+// CHECK-NEXT: ret void
diff --git a/test/CodeGenObjCXX/arc-mangle.mm b/test/CodeGenObjCXX/arc-mangle.mm
new file mode 100644
index 000000000000..1955348f1c32
--- /dev/null
+++ b/test/CodeGenObjCXX/arc-mangle.mm
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fobjc-arc -fobjc-runtime-has-weak -emit-llvm -o - %s | FileCheck %s
+
+// CHECK: define void @_Z1fPU8__strongP11objc_object(i8**)
+void f(__strong id *) {}
+// CHECK: define void @_Z1fPU6__weakP11objc_object(i8**)
+void f(__weak id *) {}
+// CHECK: define void @_Z1fPU15__autoreleasingP11objc_object(i8**)
+void f(__autoreleasing id *) {}
+// CHECK: define void @_Z1fPP11objc_object(i8**)
+void f(__unsafe_unretained id *) {}
+// CHECK: define void @_Z1fPKU8__strongP11objc_object(i8**)
+void f(const __strong id *) {}
+// CHECK: define void @_Z1fPKU6__weakP11objc_object(i8**)
+void f(const __weak id *) {}
+// CHECK: define void @_Z1fPKU15__autoreleasingP11objc_object(i8**)
+void f(const __autoreleasing id *) {}
+// CHECK: define void @_Z1fPKP11objc_object(i8**)
+void f(const __unsafe_unretained id *) {}
+
+
+template<unsigned N> struct unsigned_c { };
+
+// CHECK: define weak_odr void @_Z1gIKvEvP10unsigned_cIXplszv1U8__bridgecvPT_v1U8__bridgecvP11objc_objectcvS3_Li0ELi1EEE
+template<typename T>void g(unsigned_c<sizeof((__bridge T*)(__bridge id)(T*)0) + 1>*) {}
+template void g<const void>(unsigned_c<sizeof(id) + 1> *);
diff --git a/test/CodeGenObjCXX/arc-move.mm b/test/CodeGenObjCXX/arc-move.mm
new file mode 100644
index 000000000000..70469e6a8586
--- /dev/null
+++ b/test/CodeGenObjCXX/arc-move.mm
@@ -0,0 +1,75 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -fblocks -fobjc-arc -O2 -std=c++0x -disable-llvm-optzns -o - %s | FileCheck %s
+
+// define void @_Z11simple_moveRU8__strongP11objc_objectS2_
+void simple_move(__strong id &x, __strong id &y) {
+ // CHECK: = load i8**
+ // CHECK: store i8* null
+ // CHECK: = load i8**
+ // CHECK: store i8*
+ // CHECK-NEXT: call void @objc_release
+ x = static_cast<__strong id&&>(y);
+ // CHECK-NEXT: ret void
+}
+
+template<typename T>
+struct remove_reference {
+ typedef T type;
+};
+
+template<typename T>
+struct remove_reference<T&> {
+ typedef T type;
+};
+
+template<typename T>
+struct remove_reference<T&&> {
+ typedef T type;
+};
+
+template<typename T>
+typename remove_reference<T>::type&& move(T &&x) {
+ return static_cast<typename remove_reference<T>::type&&>(x);
+}
+
+// CHECK: define void @_Z12library_moveRU8__strongP11objc_objectS2_
+void library_move(__strong id &x, __strong id &y) {
+ // CHECK: call i8** @_Z4moveIRU8__strongP11objc_objectEON16remove_referenceIT_E4typeEOS5_
+ // CHECK: load i8**
+ // CHECK: store i8* null, i8**
+ // CHECK: load i8***
+ // CHECK-NEXT: load i8**
+ // CHECK-NEXT: store i8*
+ // CHECK-NEXT: call void @objc_release
+ // CHECK-NEXT: ret void
+ x = move(y);
+}
+
+// CHECK: define void @_Z12library_moveRU8__strongP11objc_object
+void library_move(__strong id &y) {
+ // CHECK: [[Y:%[a-zA-Z0-9]+]] = call i8** @_Z4moveIRU8__strongP11objc_objectEON16remove_referenceIT_E4typeEOS5_
+ // Load the object
+ // CHECK-NEXT: [[OBJ:%[a-zA-Z0-9]+]] = load i8** [[Y]]
+ // Null out y
+ // CHECK-NEXT: store i8* null, i8** [[Y]]
+ // Initialize x with the object
+ // CHECK-NEXT: store i8* [[OBJ]], i8** [[X:%[a-zA-Z0-9]+]]
+ id x = move(y);
+
+ // CHECK-NEXT: store i32 17
+ int i = 17;
+ // CHECK-NEXT: [[OBJ:%[a-zA-Z0-9]+]] = load i8** [[X]]
+ // CHECK-NEXT: call void @objc_release(i8* [[OBJ]])
+ // CHECK-NEXT: ret void
+}
+
+// CHECK: define void @_Z10const_moveRKU8__strongP11objc_object(
+void const_move(const __strong id &x) {
+ // CHECK: [[Y:%.*]] = alloca i8*,
+ // CHECK: [[X:%.*]] = call i8** @_Z4moveIRKU8__strongP11objc_objectEON16remove_referenceIT_E4typeEOS5_(
+ // CHECK-NEXT: [[T0:%.*]] = load i8** [[X]]
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]])
+ // CHECK-NEXT: store i8* [[T1]], i8** [[Y]]
+ // CHECK-NEXT: [[T0:%.*]] = load i8** [[Y]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T0]])
+ id y = move(x);
+}
diff --git a/test/CodeGenObjCXX/arc-new-delete.mm b/test/CodeGenObjCXX/arc-new-delete.mm
new file mode 100644
index 000000000000..4597985f8dfe
--- /dev/null
+++ b/test/CodeGenObjCXX/arc-new-delete.mm
@@ -0,0 +1,95 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fobjc-arc -fobjc-runtime-has-weak -fblocks -triple x86_64-apple-darwin10.0.0 -emit-llvm -o - %s | FileCheck %s
+
+typedef __strong id strong_id;
+typedef __weak id weak_id;
+
+// CHECK: define void @_Z8test_newP11objc_object
+void test_new(id invalue) {
+ // CHECK: alloca i8*
+ // CHECK-NEXT: call i8* @objc_retain
+
+ // CHECK: call noalias i8* @_Znwm
+ // CHECK-NEXT: {{bitcast i8\*.*to i8\*\*}}
+ // CHECK-NEXT: store i8* null, i8**
+ new strong_id;
+ // CHECK: call noalias i8* @_Znwm
+ // CHECK-NEXT: {{bitcast i8\*.*to i8\*\*}}
+ // CHECK-NEXT: store i8* null, i8**
+ new weak_id;
+
+ // CHECK: call noalias i8* @_Znwm
+ // CHECK-NEXT: {{bitcast i8\*.*to i8\*\*}}
+ // CHECK-NEXT: store i8* null, i8**
+ new __strong id;
+ // CHECK: call noalias i8* @_Znwm
+ // CHECK-NEXT: {{bitcast i8\*.*to i8\*\*}}
+ // CHECK-NEXT: store i8* null, i8**
+ new __weak id;
+
+ // CHECK: call noalias i8* @_Znwm
+ // CHECK: call i8* @objc_retain
+ // CHECK: store i8*
+ new __strong id(invalue);
+
+ // CHECK: call noalias i8* @_Znwm
+ // CHECK: call i8* @objc_initWeak
+ new __weak id(invalue);
+
+ // CHECK: call void @objc_release
+ // CHECK: ret void
+}
+
+// CHECK: define void @_Z14test_array_new
+void test_array_new() {
+ // CHECK: call noalias i8* @_Znam
+ // CHECK: store i64 17, i64*
+ // CHECK: call void @llvm.memset.p0i8.i64
+ new strong_id[17];
+
+ // CHECK: call noalias i8* @_Znam
+ // CHECK: store i64 17, i64*
+ // CHECK: call void @llvm.memset.p0i8.i64
+ new weak_id[17];
+ // CHECK: ret void
+}
+
+// CHECK: define void @_Z11test_deletePU8__strongP11objc_objectPU6__weakS0_
+void test_delete(__strong id *sptr, __weak id *wptr) {
+ // CHECK: br i1
+ // CHECK: load i8**
+ // CHECK-NEXT: call void @objc_release
+ // CHECK: call void @_ZdlPv
+ delete sptr;
+
+ // CHECK: call void @objc_destroyWeak
+ // CHECK: call void @_ZdlPv
+ delete wptr;
+
+ // CHECK: ret void
+}
+
+// CHECK: define void @_Z17test_array_deletePU8__strongP11objc_objectPU6__weakS0_
+void test_array_delete(__strong id *sptr, __weak id *wptr) {
+ // CHECK: icmp eq i8** [[BEGIN:%.*]], null
+ // CHECK: [[LEN:%.*]] = load i64* {{%.*}}
+ // CHECK: [[END:%.*]] = getelementptr inbounds i8** [[BEGIN]], i64 [[LEN]]
+ // CHECK-NEXT: icmp eq i8** [[BEGIN]], [[END]]
+ // CHECK: [[PAST:%.*]] = phi i8** [ [[END]], {{%.*}} ], [ [[CUR:%.*]],
+ // CHECK-NEXT: [[CUR]] = getelementptr inbounds i8** [[PAST]], i64 -1
+ // CHECK-NEXT: [[T0:%.*]] = load i8** [[CUR]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T0]])
+ // CHECK-NEXT: icmp eq i8** [[CUR]], [[BEGIN]]
+ // CHECK: call void @_ZdaPv
+ delete [] sptr;
+
+ // CHECK: icmp eq i8** [[BEGIN:%.*]], null
+ // CHECK: [[LEN:%.*]] = load i64* {{%.*}}
+ // CHECK: [[END:%.*]] = getelementptr inbounds i8** [[BEGIN]], i64 [[LEN]]
+ // CHECK-NEXT: icmp eq i8** [[BEGIN]], [[END]]
+ // CHECK: [[PAST:%.*]] = phi i8** [ [[END]], {{%.*}} ], [ [[CUR:%.*]],
+ // CHECK-NEXT: [[CUR]] = getelementptr inbounds i8** [[PAST]], i64 -1
+ // CHECK-NEXT: call void @objc_destroyWeak(i8** [[CUR]])
+ // CHECK-NEXT: icmp eq i8** [[CUR]], [[BEGIN]]
+ // CHECK: call void @_ZdaPv
+ delete [] wptr;
+}
diff --git a/test/CodeGenObjCXX/arc-pseudo-destructors.mm b/test/CodeGenObjCXX/arc-pseudo-destructors.mm
new file mode 100644
index 000000000000..4023e90b7dc7
--- /dev/null
+++ b/test/CodeGenObjCXX/arc-pseudo-destructors.mm
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fobjc-arc -fobjc-runtime-has-weak -fblocks -triple x86_64-apple-darwin10.0.0 -emit-llvm -o - %s | FileCheck %s
+
+// CHECK: define void @_Z28test_objc_object_pseudo_dtorPU8__strongP11objc_objectPU6__weakS0_
+void test_objc_object_pseudo_dtor(__strong id *ptr, __weak id *wptr) {
+ // CHECK: load i8***
+ // CHECK-NEXT: load i8**
+ // CHECK-NEXT: call void @objc_release
+ ptr->~id();
+
+ // CHECK: call void @objc_destroyWeak(i8** {{%.*}})
+ wptr->~id();
+
+ // CHECK: load i8***
+ // CHECK-NEXT: load i8**
+ // CHECK-NEXT: call void @objc_release
+ (*ptr).~id();
+
+ // CHECK: call void @objc_destroyWeak(i8** {{%.*}})
+ (*wptr).~id();
+ // CHECK: ret void
+}
diff --git a/test/CodeGenObjCXX/arc-references.mm b/test/CodeGenObjCXX/arc-references.mm
new file mode 100644
index 000000000000..3d0313d13ac8
--- /dev/null
+++ b/test/CodeGenObjCXX/arc-references.mm
@@ -0,0 +1,83 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -fobjc-runtime-has-weak -fblocks -fobjc-arc -O2 -disable-llvm-optzns -o - %s | FileCheck %s
+
+@interface A
+@end
+
+id getObject();
+void callee();
+
+// Lifetime extension for binding a reference to an rvalue
+// CHECK: define void @_Z5test0v()
+void test0() {
+ // CHECK: call i8* @_Z9getObjectv
+ // CHECK-NEXT:: call i8* @objc_retainAutoreleasedReturnValue
+ const __strong id &ref1 = getObject();
+ // CHECK: call void @_Z6calleev
+ callee();
+ // CHECK: call i8* @_Z9getObjectv
+ // CHECK-NEXT: call i8* @objc_retainAutoreleasedReturnValue
+ // CHECK-NEXT: call i8* @objc_autorelease
+ const __autoreleasing id &ref2 = getObject();
+ // CHECK: call void @_Z6calleev
+ callee();
+ // CHECK: call void @objc_release
+ // CHECK-NEXT: ret
+}
+
+// No lifetime extension when we're binding a reference to an lvalue.
+// CHECK: define void @_Z5test1RU8__strongP11objc_objectRU6__weakS0_
+void test1(__strong id &x, __weak id &y) {
+ // CHECK-NOT: release
+ const __strong id &ref1 = x;
+ const __autoreleasing id &ref2 = x;
+ const __weak id &ref3 = y;
+ // CHECK: ret void
+}
+
+typedef __strong id strong_id;
+
+//CHECK: define void @_Z5test3v
+void test3() {
+ // CHECK: call i8* @objc_initWeak
+ // CHECK-NEXT: store i8**
+ const __weak id &ref = strong_id();
+ // CHECK-NEXT: call void @_Z6calleev()
+ callee();
+ // CHECK-NEXT: call void @objc_destroyWeak
+ // CHECK-NEXT: ret void
+}
+
+// CHECK: define void @_Z5test4RU8__strongP11objc_object
+void test4(__strong id &x) {
+ // CHECK: call i8* @objc_retain
+ __strong A* const &ar = x;
+ // CHECK: store i32 17, i32*
+ int i = 17;
+ // CHECK: call void @objc_release(
+ // CHECK: ret void
+}
+
+void sink(__strong A* &&);
+
+// CHECK: define void @_Z5test5RU8__strongP11objc_object
+void test5(__strong id &x) {
+ // CHECK: [[OBJ_ID:%[a-zA-Z0-9]+]] = call i8* @objc_retain
+ // CHECK-NEXT: [[OBJ_A:%[a-zA-Z0-9]+]] = bitcast i8* [[OBJ_ID]] to [[A:%[a-zA-Z0-9]+]]*
+ // CHECK-NEXT: store [[A]]* [[OBJ_A]], [[A]]** [[REFTMP:%[a-zA-Z0-9]+]]
+ // CHECK-NEXT: call void @_Z4sinkOU8__strongP1A
+ sink(x);
+ // CHECK-NEXT: [[OBJ_A:%[a-zA-Z0-9]+]] = load [[A]]** [[REFTMP]]
+ // CHECK-NEXT: [[OBJ_ID:%[a-zA-Z0-9]+]] = bitcast [[A]]* [[OBJ_A]] to i8*
+ // CHECK-NEXT: call void @objc_release
+ // CHECK-NEXT: store i32 17, i32
+ int i = 17;
+ // CHECK-NEXT: ret void
+}
+
+// CHECK: define internal void @__cxx_global_var_init(
+// CHECK: call i8* @_Z9getObjectv
+// CHECK-NEXT: call i8* @objc_retainAutoreleasedReturnValue
+const __strong id &global_ref = getObject();
+
+// Note: we intentionally don't release the object.
+
diff --git a/test/CodeGenObjCXX/arc-special-member-functions.mm b/test/CodeGenObjCXX/arc-special-member-functions.mm
new file mode 100644
index 000000000000..d88a2bd62ffc
--- /dev/null
+++ b/test/CodeGenObjCXX/arc-special-member-functions.mm
@@ -0,0 +1,161 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fobjc-arc -fblocks -triple x86_64-apple-darwin10.0.0 -emit-llvm -o - %s | FileCheck %s
+
+struct ObjCMember {
+ id member;
+};
+
+struct ObjCArrayMember {
+ id member[2][3];
+};
+
+struct ObjCBlockMember {
+ int (^bp)(int);
+};
+
+// CHECK: define void @_Z42test_ObjCMember_default_construct_destructv(
+void test_ObjCMember_default_construct_destruct() {
+ // CHECK: call void @_ZN10ObjCMemberC1Ev
+ // CHECK: call void @_ZN10ObjCMemberD1Ev
+ ObjCMember m1;
+}
+
+// CHECK: define void @_Z39test_ObjCMember_copy_construct_destruct10ObjCMember
+void test_ObjCMember_copy_construct_destruct(ObjCMember m1) {
+ // CHECK: call void @_ZN10ObjCMemberC1ERKS_
+ // CHECK: call void @_ZN10ObjCMemberD1Ev
+ ObjCMember m2 = m1;
+ // CHECK: ret void
+}
+
+// CHECK: define void @_Z27test_ObjCMember_copy_assign10ObjCMemberS_
+void test_ObjCMember_copy_assign(ObjCMember m1, ObjCMember m2) {
+ // CHECK: {{call.*_ZN10ObjCMemberaSERKS_}}
+ m1 = m2;
+ // CHECK-NEXT: ret void
+}
+
+// Implicitly-generated copy assignment operator for ObjCMember
+// CHECK: {{define linkonce_odr.*@_ZN10ObjCMemberaSERKS_}}
+// CHECK: call void @objc_storeStrong
+// CHECK: ret
+
+// CHECK: define void @_Z47test_ObjCArrayMember_default_construct_destructv
+void test_ObjCArrayMember_default_construct_destruct() {
+ // CHECK: call void @_ZN15ObjCArrayMemberC1Ev
+ ObjCArrayMember m1;
+ // CHECK: call void @_ZN15ObjCArrayMemberD1Ev
+ // CHECK: ret void
+}
+
+// CHECK: define void @_Z44test_ObjCArrayMember_copy_construct_destruct15ObjCArrayMember
+void test_ObjCArrayMember_copy_construct_destruct(ObjCArrayMember m1) {
+ // CHECK: call void @_ZN15ObjCArrayMemberC1ERKS_
+ ObjCArrayMember m2 = m1;
+ // CHECK: call void @_ZN15ObjCArrayMemberD1Ev
+ // CHECK: ret void
+}
+
+void test_ObjCArrayMember_copy_assign(ObjCArrayMember m1, ObjCArrayMember m2) {
+ // CHECK: {{call.*@_ZN15ObjCArrayMemberaSERKS_}}
+ m1 = m2;
+ // CHECK-NEXT: ret void
+}
+
+// Implicitly-generated copy assignment operator for ObjCArrayMember
+// CHECK: {{define linkonce_odr.*@_ZN15ObjCArrayMemberaSERKS_}}
+// CHECK: call void @objc_storeStrong
+// CHECK-NEXT: br label
+// CHECK: ret
+
+// CHECK: define void @_Z47test_ObjCBlockMember_default_construct_destructv
+void test_ObjCBlockMember_default_construct_destruct() {
+ // CHECK: call void @_ZN15ObjCBlockMemberC1Ev
+ ObjCBlockMember m;
+ // CHECK-NEXT: call void @_ZN15ObjCBlockMemberD1Ev
+ // CHECK-NEXT: ret void
+}
+
+// CHECK: define void @_Z44test_ObjCBlockMember_copy_construct_destruct15ObjCBlockMember
+void test_ObjCBlockMember_copy_construct_destruct(ObjCBlockMember m1) {
+ // CHECK: call void @_ZN15ObjCBlockMemberC1ERKS_
+ ObjCBlockMember m2 = m1;
+ // CHECK-NEXT: call void @_ZN15ObjCBlockMemberD1Ev
+ // CHECK-NEXT: ret void
+}
+
+// CHECK: define void @_Z32test_ObjCBlockMember_copy_assign15ObjCBlockMemberS_
+void test_ObjCBlockMember_copy_assign(ObjCBlockMember m1, ObjCBlockMember m2) {
+ // CHECK: {{call.*_ZN15ObjCBlockMemberaSERKS_}}
+ m1 = m2;
+ // CHECK-NEXT: ret void
+}
+
+// Implicitly-generated copy assignment operator for ObjCBlockMember
+// CHECK: define linkonce_odr {{%.*}}* @_ZN15ObjCBlockMemberaSERKS_(
+// CHECK: [[T0:%.*]] = call i8* @objc_retainBlock(
+// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to i32 (i32)*
+// CHECK-NEXT: [[T2:%.*]] = load {{.*}} [[SLOT:%.*]],
+// CHECK: store
+// CHECK-NEXT: [[T3:%.*]] = bitcast
+// CHECK-NEXT: call void @objc_release(i8* [[T3]])
+// CHECK-NEXT: ret
+
+// Implicitly-generated copy constructor for ObjCBlockMember
+// CHECK: define linkonce_odr void @_ZN15ObjCBlockMemberC2ERKS_
+// CHECK: call i8* @objc_retainBlock
+// CHECK: ret
+
+// Implicitly-generated destructor for ObjCBlockMember
+// CHECK: define linkonce_odr void @_ZN15ObjCBlockMemberD2Ev
+// CHECK: call void @objc_release(i8*
+// CHECK: ret
+
+// Implicitly-generated default constructor for ObjCBlockMember
+// CHECK: define linkonce_odr void @_ZN15ObjCBlockMemberC2Ev
+// CHECK: store {{.*}} null,
+// CHECK-NEXT: ret void
+
+// Implicitly-generated copy constructor for ObjCArrayMember
+// CHECK: define linkonce_odr void @_ZN15ObjCArrayMemberC2ERKS_
+// CHECK: br i1
+// CHECK: call i8* @objc_retain
+// CHECK-NEXT: store i8*
+// CHECK-NEXT: br label
+// CHECK: ret
+
+// Implicitly-generated destructor for ObjCArrayMember
+// CHECK: define linkonce_odr void @_ZN15ObjCArrayMemberD2Ev
+// CHECK: [[BEGIN:%.*]] = getelementptr inbounds [2 x [3 x i8*]]*
+// CHECK-NEXT: [[END:%.*]] = getelementptr inbounds i8** [[BEGIN]], i64 6
+// CHECK-NEXT: br label
+// CHECK: [[PAST:%.*]] = phi i8** [ [[END]], {{%.*}} ], [ [[CUR:%.*]], {{%.*}} ]
+// CHECK-NEXT: [[CUR]] = getelementptr inbounds i8** [[PAST]], i64 -1
+// CHECK-NEXT: [[T0:%.*]] = load i8** [[CUR]]
+// CHECK-NEXT: call void @objc_release(i8* [[T0]])
+// CHECK-NEXT: [[T1:%.*]] = icmp eq i8** [[CUR]], [[BEGIN]]
+// CHECK-NEXT: br i1 [[T1]],
+// CHECK: ret void
+
+// Implicitly-generated default constructor for ObjCArrayMember
+// CHECK: define linkonce_odr void @_ZN15ObjCArrayMemberC2Ev
+// CHECK: call void @llvm.memset.p0i8.i64
+// CHECK: ret
+
+// Implicitly-generated copy constructor for ObjCMember
+// CHECK: define linkonce_odr void @_ZN10ObjCMemberC2ERKS_
+// CHECK-NOT: objc_release
+// CHECK: call i8* @objc_retain
+// CHECK-NEXT: store i8*
+// CHECK-NEXT: ret void
+
+// Implicitly-generated destructor for ObjCMember
+// CHECK: define linkonce_odr void @_ZN10ObjCMemberD2Ev
+// CHECK: call void @objc_release
+// CHECK: ret void
+
+// Implicitly-generated default constructor for ObjCMember
+// CHECK: define linkonce_odr void @_ZN10ObjCMemberC2Ev
+// CHECK-NOT: objc_release
+// CHECK: store i8* null
+// CHECK-NEXT: ret void
+
diff --git a/test/CodeGenObjCXX/arc.mm b/test/CodeGenObjCXX/arc.mm
new file mode 100644
index 000000000000..0c5466a4cea3
--- /dev/null
+++ b/test/CodeGenObjCXX/arc.mm
@@ -0,0 +1,166 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -fobjc-runtime-has-weak -fblocks -fobjc-arc -O2 -disable-llvm-optzns -o - %s | FileCheck %s
+
+// rdar://problem/9315552
+// The analogous ObjC testcase test46 in arr.m.
+void test0(__weak id *wp, __weak volatile id *wvp) {
+ extern id test0_helper(void);
+
+ // TODO: this is sub-optimal, we should retain at the actual call site.
+ // TODO: in the non-volatile case, we do not need to be reloading.
+
+ // CHECK: [[T0:%.*]] = call i8* @_Z12test0_helperv()
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
+ // CHECK-NEXT: [[T2:%.*]] = load i8*** {{%.*}}, align 8
+ // CHECK-NEXT: [[T3:%.*]] = call i8* @objc_storeWeak(i8** [[T2]], i8* [[T1]])
+ // CHECK-NEXT: [[T4:%.*]] = call i8* @objc_retain(i8* [[T3]])
+ // CHECK-NEXT: store i8* [[T4]], i8**
+ // CHECK-NEXT: call void @objc_release(i8* [[T1]])
+ id x = *wp = test0_helper();
+
+ // CHECK: [[T0:%.*]] = call i8* @_Z12test0_helperv()
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
+ // CHECK-NEXT: [[T2:%.*]] = load i8*** {{%.*}}, align 8
+ // CHECK-NEXT: [[T3:%.*]] = call i8* @objc_storeWeak(i8** [[T2]], i8* [[T1]])
+ // CHECK-NEXT: [[T4:%.*]] = call i8* @objc_loadWeakRetained(i8** [[T2]])
+ // CHECK-NEXT: store i8* [[T4]], i8**
+ // CHECK-NEXT: call void @objc_release(i8* [[T1]])
+ id y = *wvp = test0_helper();
+}
+
+// rdar://problem/9320648
+struct Test1_helper { Test1_helper(); };
+@interface Test1 @end
+@implementation Test1 { Test1_helper x; } @end
+// CHECK: define internal i8* @"\01-[Test1 .cxx_construct]"(
+// CHECK: call void @_ZN12Test1_helperC1Ev(
+// CHECK-NEXT: load
+// CHECK-NEXT: bitcast
+// CHECK-NEXT: ret i8*
+
+void test34(int cond) {
+ __strong id strong;
+ __weak id weak;
+ extern void test34_sink(id *);
+ test34_sink(cond ? &strong : 0);
+ test34_sink(cond ? &weak : 0);
+
+ // CHECK: define void @_Z6test34i(
+ // CHECK: [[COND:%.*]] = alloca i32
+ // CHECK-NEXT: [[STRONG:%.*]] = alloca i8*
+ // CHECK-NEXT: [[WEAK:%.*]] = alloca i8*
+ // CHECK-NEXT: [[TEMP1:%.*]] = alloca i8*
+ // CHECK-NEXT: [[TEMP2:%.*]] = alloca i8*
+ // CHECK-NEXT: store i32
+ // CHECK-NEXT: store i8* null, i8** [[STRONG]]
+ // CHECK-NEXT: call i8* @objc_initWeak(i8** [[WEAK]], i8* null)
+
+ // CHECK-NEXT: [[T0:%.*]] = load i32* [[COND]]
+ // CHECK-NEXT: [[T1:%.*]] = icmp ne i32 [[T0]], 0
+ // CHECK: [[ARG:%.*]] = phi i8**
+ // CHECK-NEXT: [[T0:%.*]] = icmp eq i8** [[ARG]], null
+ // CHECK-NEXT: [[T1:%.*]] = select i1 [[T0]], i8** null, i8** [[TEMP1]]
+ // CHECK-NEXT: br i1 [[T0]],
+ // CHECK: [[T0:%.*]] = load i8** [[ARG]]
+ // CHECK-NEXT: store i8* [[T0]], i8** [[TEMP1]]
+ // CHECK-NEXT: br label
+ // CHECK: call void @_Z11test34_sinkPU15__autoreleasingP11objc_object(i8** [[T1]])
+ // CHECK-NEXT: [[T0:%.*]] = icmp eq i8** [[ARG]], null
+ // CHECK-NEXT: br i1 [[T0]],
+ // CHECK: [[T0:%.*]] = load i8** [[TEMP1]]
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]])
+ // CHECK-NEXT: [[T2:%.*]] = load i8** [[ARG]]
+ // CHECK-NEXT: store i8* [[T1]], i8** [[ARG]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T2]])
+ // CHECK-NEXT: br label
+
+ // CHECK: [[T0:%.*]] = load i32* [[COND]]
+ // CHECK-NEXT: [[T1:%.*]] = icmp ne i32 [[T0]], 0
+ // CHECK: [[ARG:%.*]] = phi i8**
+ // CHECK-NEXT: [[T0:%.*]] = icmp eq i8** [[ARG]], null
+ // CHECK-NEXT: [[T1:%.*]] = select i1 [[T0]], i8** null, i8** [[TEMP2]]
+ // CHECK-NEXT: br i1 [[T0]],
+ // CHECK: [[T0:%.*]] = call i8* @objc_loadWeak(i8** [[ARG]])
+ // CHECK-NEXT: store i8* [[T0]], i8** [[TEMP2]]
+ // CHECK-NEXT: br label
+ // CHECK: call void @_Z11test34_sinkPU15__autoreleasingP11objc_object(i8** [[T1]])
+ // CHECK-NEXT: [[T0:%.*]] = icmp eq i8** [[ARG]], null
+ // CHECK-NEXT: br i1 [[T0]],
+ // CHECK: [[T0:%.*]] = load i8** [[TEMP2]]
+ // CHECK-NEXT: call i8* @objc_storeWeak(i8** [[ARG]], i8* [[T0]])
+ // CHECK-NEXT: br label
+
+ // CHECK: call void @objc_destroyWeak(i8** [[WEAK]])
+ // CHECK: ret void
+}
+
+struct Test35_Helper {
+ static id makeObject1() __attribute__((ns_returns_retained));
+ id makeObject2() __attribute__((ns_returns_retained));
+ static id makeObject3();
+ id makeObject4();
+};
+
+// CHECK: define void @_Z6test3513Test35_HelperPS_
+void test35(Test35_Helper x0, Test35_Helper *x0p) {
+ // CHECK: call i8* @_ZN13Test35_Helper11makeObject1Ev
+ // CHECK-NOT: call i8* @objc_retain
+ id obj1 = Test35_Helper::makeObject1();
+ // CHECK: call i8* @_ZN13Test35_Helper11makeObject2Ev
+ // CHECK-NOT: call i8* @objc_retain
+ id obj2 = x0.makeObject2();
+ // CHECK: call i8* @_ZN13Test35_Helper11makeObject2Ev
+ // CHECK-NOT: call i8* @objc_retain
+ id obj3 = x0p->makeObject2();
+ id (Test35_Helper::*pmf)() __attribute__((ns_returns_retained))
+ = &Test35_Helper::makeObject2;
+ // CHECK: call i8* %
+ // CHECK-NOT: call i8* @objc_retain
+ id obj4 = (x0.*pmf)();
+ // CHECK: call i8* %
+ // CHECK-NOT: call i8* @objc_retain
+ id obj5 = (x0p->*pmf)();
+
+ // CHECK: call void @objc_release
+ // CHECK: call void @objc_release
+ // CHECK: call void @objc_release
+ // CHECK: call void @objc_release
+ // CHECK: call void @objc_release
+ // CHECK-NEXT: ret void
+}
+
+// CHECK: define void @_Z7test35b13Test35_HelperPS_
+void test35b(Test35_Helper x0, Test35_Helper *x0p) {
+ // CHECK: call i8* @_ZN13Test35_Helper11makeObject3Ev
+ // CHECK: call i8* @objc_retain
+ id obj1 = Test35_Helper::makeObject3();
+ // CHECK: call i8* @_ZN13Test35_Helper11makeObject4Ev
+ // CHECK: call i8* @objc_retain
+ id obj2 = x0.makeObject4();
+ // CHECK: call i8* @_ZN13Test35_Helper11makeObject4Ev
+ // CHECK: call i8* @objc_retain
+ id obj3 = x0p->makeObject4();
+ id (Test35_Helper::*pmf)() = &Test35_Helper::makeObject4;
+ // CHECK: call i8* %
+ // CHECK: call i8* @objc_retain
+ id obj4 = (x0.*pmf)();
+ // CHECK: call i8* %
+ // CHECK: call i8* @objc_retain
+ id obj5 = (x0p->*pmf)();
+
+ // CHECK: call void @objc_release
+ // CHECK: call void @objc_release
+ // CHECK: call void @objc_release
+ // CHECK: call void @objc_release
+ // CHECK: call void @objc_release
+ // CHECK-NEXT: ret void
+}
+
+// rdar://problem/9603128
+// CHECK: define i8* @_Z6test36P11objc_object(
+id test36(id z) {
+ // CHECK: objc_retain
+ // CHECK: objc_retain
+ // CHECK: objc_release
+ // CHECK: objc_autoreleaseReturnValue
+ return z;
+}
diff --git a/test/CodeGenObjCXX/catch-id-type.mm b/test/CodeGenObjCXX/catch-id-type.mm
new file mode 100644
index 000000000000..ece342bb8720
--- /dev/null
+++ b/test/CodeGenObjCXX/catch-id-type.mm
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -triple i386-apple-macosx10.6.6 -emit-llvm -fobjc-exceptions -fcxx-exceptions -fexceptions -o - %s | FileCheck %s
+// rdar://8940528
+
+@interface ns_array
++ (id) array;
+@end
+
+@implementation ns_array
++ (id) array { return 0; }
+@end
+
+id Groups();
+
+@protocol P @end;
+
+@interface INTF<P> {
+ double dd;
+}
+@end
+
+id FUNC() {
+ id groups;
+ try
+ {
+ groups = Groups(); // throws on errors.
+ }
+ catch( INTF<P>* error )
+ {
+ Groups();
+ }
+ catch( id error )
+ {
+ // CHECK: call i32 (i8*, i8*, ...)* @llvm.eh.selector({{.*}} @__gxx_personality_v0 {{.*}} @_ZTIP4INTF {{.*}} @_ZTIP11objc_object {{.*}} @_ZTIP10objc_class
+ error = error;
+ groups = [ns_array array];
+ }
+ catch (Class cl) {
+ cl = cl;
+ groups = [ns_array array];
+ }
+ return groups;
+
+}
+
+int main() {
+ FUNC();
+ return 0;
+}
diff --git a/test/CodeGenObjCXX/copy.mm b/test/CodeGenObjCXX/copy.mm
new file mode 100644
index 000000000000..133910f25dcf
--- /dev/null
+++ b/test/CodeGenObjCXX/copy.mm
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
+
+// rdar://problem/9158302
+// This should not use a memmove_collectable in non-GC mode.
+namespace test0 {
+ struct A {
+ id x;
+ };
+
+ // CHECK: define [[A:%.*]]* @_ZN5test04testENS_1AE(
+ // CHECK: alloca
+ // CHECK-NEXT: getelementptr
+ // CHECK-NEXT: store
+ // CHECK-NEXT: call noalias i8* @_Znwm(
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: call void @llvm.memset.p0i8.i64(
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(
+ // CHECK-NEXT: ret
+ A *test(A a) {
+ return new A(a);
+ }
+}
+
diff --git a/test/CodeGenObjCXX/encode.mm b/test/CodeGenObjCXX/encode.mm
index dce3d70665de..2c10fbcb9753 100644
--- a/test/CodeGenObjCXX/encode.mm
+++ b/test/CodeGenObjCXX/encode.mm
@@ -91,6 +91,20 @@ namespace rdar9357400 {
const char gg[] = @encode(vector4f);
}
+// rdar://9624314
+namespace rdar9624314 {
+ struct B2 { int x; };
+ struct B3 {};
+ struct S : B2, B3 {};
+
+ // CHECK: @_ZN11rdar9624314L2ggE = internal constant [6 x i8] c"{S=i}\00"
+ const char gg[] = @encode(S);
+
+ struct S2 { unsigned : 0; int x; unsigned : 0; };
+ // CHECK: @_ZN11rdar9624314L2g2E = internal constant [11 x i8] c"{S2=b0ib0}\00"
+ const char g2[] = @encode(S2);
+}
+
struct Base1 {
char x;
};
diff --git a/test/CodeGenObjCXX/gc.mm b/test/CodeGenObjCXX/gc.mm
new file mode 100644
index 000000000000..aa293dacf3a7
--- /dev/null
+++ b/test/CodeGenObjCXX/gc.mm
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -fobjc-gc -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
+
+namespace test0 {
+ extern id x;
+
+ struct A {
+ id x;
+ A();
+ };
+ A::A() : x(test0::x) {}
+
+// CHECK: define void @_ZN5test01AC2Ev(
+// CHECK: [[THIS:%.*]] = alloca [[TEST0:%.*]]*, align 8
+// CHECK-NEXT: store
+// CHECK-NEXT: [[T0:%.*]] = load [[TEST0]]** [[THIS]]
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[TEST0]]* [[T0]], i32 0, i32 0
+// CHECK-NEXT: [[T2:%.*]] = load i8** @_ZN5test01xE
+// CHECK-NEXT: call i8* @objc_assign_strongCast(i8* [[T2]], i8** [[T1]])
+// CHECK-NEXT: ret void
+}
diff --git a/test/CodeGenObjCXX/property-object-conditional-exp.mm b/test/CodeGenObjCXX/property-object-conditional-exp.mm
index a3c1027ed709..5d8a8826355c 100644
--- a/test/CodeGenObjCXX/property-object-conditional-exp.mm
+++ b/test/CodeGenObjCXX/property-object-conditional-exp.mm
@@ -22,11 +22,12 @@ extern "C" bool CGRectIsEmpty(CGRect);
CGRect dataRect;
CGRect virtualBounds;
-// CHECK: [[SRC:%.*]] = call %struct.CGRect bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
-// CHECK-NEXT:getelementptr %struct.CGRect* [[SRC:%.*]]
+// CHECK: [[SRC:%.*]] = call { i8*, i32 } bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
+// CHECK-NEXT: bitcast
+// CHECK-NEXT:getelementptr { i8*, i32 }* [[SRC:%.*]]
// CHECK-NEXT:extractvalue
// CHECK-NEXT:store
-// CHECK-NEXT:getelementptr %struct.CGRect* [[SRC:%.*]]
+// CHECK-NEXT:getelementptr { i8*, i32 }* [[SRC:%.*]]
// CHECK-NEXT:extractvalue
// CHECK-NEXT:store
dataRect = CGRectIsEmpty(virtualBounds) ? self.bounds : virtualBounds;
diff --git a/test/CodeGenObjCXX/property-objects.mm b/test/CodeGenObjCXX/property-objects.mm
index 8e98b0dae7e4..1f4311763595 100644
--- a/test/CodeGenObjCXX/property-objects.mm
+++ b/test/CodeGenObjCXX/property-objects.mm
@@ -2,7 +2,7 @@
// CHECK-NOT: callq _objc_msgSend_stret
// CHECK: call void @_ZN1SC1ERKS_
// CHECK: call %class.S* @_ZN1SaSERKS_
-// CHECK: call %class.S* @_ZN6CGRectaSERKS_
+// CHECK: call %struct.CGRect* @_ZN6CGRectaSERKS_
class S {
public:
diff --git a/test/CodeGenOpenCL/2011-04-15-vec-init-from-vec.cl b/test/CodeGenOpenCL/2011-04-15-vec-init-from-vec.cl
index c61be69b5739..fbe3d89f10b2 100644
--- a/test/CodeGenOpenCL/2011-04-15-vec-init-from-vec.cl
+++ b/test/CodeGenOpenCL/2011-04-15-vec-init-from-vec.cl
@@ -1,12 +1,11 @@
// RUN: %clang_cc1 %s -emit-llvm -o %t
typedef __attribute__((ext_vector_type(4))) unsigned char uchar4;
-typedef __attribute__((ext_vector_type(4))) unsigned int int4;
typedef __attribute__((ext_vector_type(8))) unsigned char uchar8;
// OpenCL allows vectors to be initialized by vectors Handle bug in
// VisitInitListExpr for this case below.
-void foo( int4 v )
+void foo( uchar8 x )
{
- uchar4 val[4] = {{(uchar4){((uchar8)(v.lo)).lo}}};
-} \ No newline at end of file
+ uchar4 val[4] = {{(uchar4){x.lo}}};
+}
diff --git a/test/CodeGenOpenCL/vector_literals_valid.cl b/test/CodeGenOpenCL/vector_literals_valid.cl
new file mode 100644
index 000000000000..bba5b23e23bd
--- /dev/null
+++ b/test/CodeGenOpenCL/vector_literals_valid.cl
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -emit-llvm %s -o %t
+
+typedef __attribute__(( ext_vector_type(2) )) int int2;
+typedef __attribute__(( ext_vector_type(3) )) int int3;
+typedef __attribute__(( ext_vector_type(4) )) int int4;
+typedef __attribute__(( ext_vector_type(8) )) int int8;
+typedef __attribute__(( ext_vector_type(4) )) float float4;
+
+void vector_literals_valid() {
+ int4 a_1_1_1_1 = (int4)(1,2,3,4);
+ int4 a_2_1_1 = (int4)((int2)(1,2),3,4);
+ int4 a_1_2_1 = (int4)(1,(int2)(2,3),4);
+ int4 a_1_1_2 = (int4)(1,2,(int2)(3,4));
+ int4 a_2_2 = (int4)((int2)(1,2),(int2)(3,4));
+ int4 a_3_1 = (int4)((int3)(1,2,3),4);
+ int4 a_1_3 = (int4)(1,(int3)(2,3,4));
+ int4 a = (int4)(1);
+ int8 b = (int8)(1,2,a.xy,a);
+ float4 V2 = (float4) (1);
+}
+
+
diff --git a/test/Driver/arc-exceptions.m b/test/Driver/arc-exceptions.m
new file mode 100644
index 000000000000..4501ccd07382
--- /dev/null
+++ b/test/Driver/arc-exceptions.m
@@ -0,0 +1,5 @@
+// RUN: %clang -### -x objective-c -arch x86_64 -fobjc-arc -fsyntax-only %s 2> %t.log
+// RUN: grep objective-c %t.log
+// RUN: not grep "fobjc-arc-exceptions" %t.log
+// RUN: %clang -### -x objective-c++ -arch x86_64 -fobjc-arc -fsyntax-only %s 2> %t.log
+// RUN: grep "fobjc-arc-exceptions" %t.log
diff --git a/test/Driver/arc.c b/test/Driver/arc.c
new file mode 100644
index 000000000000..a4d4ed1c6043
--- /dev/null
+++ b/test/Driver/arc.c
@@ -0,0 +1,14 @@
+// RUN: %clang -ObjC -ccc-host-triple i386-apple-darwin9 -m32 -fobjc-arc %s -fsyntax-only 2>&1 | FileCheck %s
+// RUN: %clang -x objective-c -ccc-host-triple i386-apple-darwin9 -m32 -fobjc-arc %s -fsyntax-only 2>&1 | FileCheck %s
+// RUN: %clang -x objective-c++ -ccc-host-triple i386-apple-darwin9 -m32 -fobjc-arc %s -fsyntax-only 2>&1 | FileCheck %s
+// RUN: %clang -x c -ccc-host-triple i386-apple-darwin9 -m32 -fobjc-arc %s -fsyntax-only 2>&1 | FileCheck -check-prefix NOTOBJC %s
+// RUN: %clang -x c++ -ccc-host-triple i386-apple-darwin9 -m32 -fobjc-arc %s -fsyntax-only 2>&1 | FileCheck -check-prefix NOTOBJC %s
+
+// Just to test clang is working.
+# foo
+
+// CHECK: error: -fobjc-arc is not supported with fragile abi
+// CHECK-NOT: invalid preprocessing directive
+
+// NOTOBJC-NOT: error: -fobjc-arc is not supported with fragile abi
+// NOTOBJC: invalid preprocessing directive
diff --git a/test/Driver/darwin-ld.c b/test/Driver/darwin-ld.c
index 91d47eaaf412..33b48583b5e9 100644
--- a/test/Driver/darwin-ld.c
+++ b/test/Driver/darwin-ld.c
@@ -18,9 +18,9 @@
//
// Note that at conception, this exactly matches gcc.
-// RUN: %clang -ccc-host-triple i386-apple-darwin9 -### -A ARG0 -F ARG1 -L ARG2 -Mach -T ARG4 -X -Z -all_load -allowable_client ARG8 -bind_at_load -compatibility_version ARG11 -current_version ARG12 -d -dead_strip -dylib_file ARG14 -dylinker -dylinker_install_name ARG16 -dynamic -dynamiclib -e ARG19 -exported_symbols_list ARG20 -fexceptions -flat_namespace -fnested-functions -fopenmp -force_cpusubtype_ALL -fpie -fprofile-arcs -headerpad_max_install_names -image_base ARG29 -init ARG30 -install_name ARG31 -m ARG33 -mmacosx-version-min=10.3.2 -multi_module -multiply_defined ARG37 -multiply_defined_unused ARG38 -no_dead_strip_inits_and_terms -nodefaultlibs -nofixprebinding -nomultidefs -noprebind -noseglinkedit -nostartfiles -nostdlib -pagezero_size ARG54 -pg -prebind -prebind_all_twolevel_modules -preload -r -read_only_relocs ARG55 -s -sectalign ARG57_0 ARG57_1 ARG57_2 -sectcreate ARG58_0 ARG58_1 ARG58_2 -sectobjectsymbols ARG59_0 ARG59_1 -sectorder ARG60_0 ARG60_1 ARG60_2 -seg1addr ARG61 -seg_addr_table ARG62 -seg_addr_table_filename ARG63 -segaddr ARG64_0 ARG64_1 -segcreate ARG65_0 ARG65_1 ARG65_2 -seglinkedit -segprot ARG67_0 ARG67_1 ARG67_2 -segs_read_FOO -segs_read_only_addr ARG69 -segs_read_write_addr ARG70 -shared-libgcc -single_module -static -static-libgcc -sub_library ARG77 -sub_umbrella ARG78 -t -twolevel_namespace -twolevel_namespace_hints -u ARG82 -umbrella ARG83 -undefined ARG84 -unexported_symbols_list ARG85 -w -weak_reference_mismatches ARG87 -whatsloaded -whyload -y -filelist FOO -l FOO 2> %t.log
+// RUN: %clang -ccc-host-triple i386-apple-darwin9 -### -A ARG0 -F ARG1 -L ARG2 -Mach -T ARG4 -X -Z -all_load -allowable_client ARG8 -bind_at_load -compatibility_version ARG11 -current_version ARG12 -d -dead_strip -dylib_file ARG14 -dylinker -dylinker_install_name ARG16 -dynamic -dynamiclib -e ARG19 -exported_symbols_list ARG20 -fexceptions -flat_namespace -fnested-functions -fopenmp -force_cpusubtype_ALL -force_load ARG28 -fpie -fprofile-arcs -headerpad_max_install_names -image_base ARG29 -init ARG30 -install_name ARG31 -m ARG33 -mmacosx-version-min=10.3.2 -multi_module -multiply_defined ARG37 -multiply_defined_unused ARG38 -no_dead_strip_inits_and_terms -nodefaultlibs -nofixprebinding -nomultidefs -noprebind -noseglinkedit -nostartfiles -nostdlib -pagezero_size ARG54 -pg -prebind -prebind_all_twolevel_modules -preload -r -read_only_relocs ARG55 -s -sectalign ARG57_0 ARG57_1 ARG57_2 -sectcreate ARG58_0 ARG58_1 ARG58_2 -sectobjectsymbols ARG59_0 ARG59_1 -sectorder ARG60_0 ARG60_1 ARG60_2 -seg1addr ARG61 -seg_addr_table ARG62 -seg_addr_table_filename ARG63 -segaddr ARG64_0 ARG64_1 -segcreate ARG65_0 ARG65_1 ARG65_2 -seglinkedit -segprot ARG67_0 ARG67_1 ARG67_2 -segs_read_FOO -segs_read_only_addr ARG69 -segs_read_write_addr ARG70 -shared-libgcc -single_module -static -static-libgcc -sub_library ARG77 -sub_umbrella ARG78 -t -twolevel_namespace -twolevel_namespace_hints -u ARG82 -umbrella ARG83 -undefined ARG84 -unexported_symbols_list ARG85 -w -weak_reference_mismatches ARG87 -whatsloaded -whyload -y -filelist FOO -l FOO 2> %t.log
// RUN: FileCheck -check-prefix=SPLATTER %s < %t.log
-// SPLATTER: {{".*ld.*" "-static" "-dylib" "-dylib_compatibility_version" "ARG11" "-dylib_current_version" "ARG12" "-arch" "i386" "-dylib_install_name" "ARG31" "-all_load" "-allowable_client" "ARG8" "-bind_at_load" "-dead_strip" "-no_dead_strip_inits_and_terms" "-dylib_file" "ARG14" "-dynamic" "-exported_symbols_list" "ARG20" "-flat_namespace" "-headerpad_max_install_names" "-image_base" "ARG29" "-init" "ARG30" "-macosx_version_min" "10.3.2" "-nomultidefs" "-multi_module" "-single_module" "-multiply_defined" "ARG37" "-multiply_defined_unused" "ARG38" "-pie" "-prebind" "-noprebind" "-nofixprebinding" "-prebind_all_twolevel_modules" "-read_only_relocs" "ARG55" "-sectcreate" "ARG58_0" "ARG58_1" "ARG58_2" "-sectorder" "ARG60_0" "ARG60_1" "ARG60_2" "-seg1addr" "ARG61" "-segprot" "ARG67_0" "ARG67_1" "ARG67_2" "-segaddr" "ARG64_0" "ARG64_1" "-segs_read_only_addr" "ARG69" "-segs_read_write_addr" "ARG70" "-seg_addr_table" "ARG62" "-seg_addr_table_filename" "ARG63" "-sub_library" "ARG77" "-sub_umbrella" "ARG78" "-twolevel_namespace" "-twolevel_namespace_hints" "-umbrella" "ARG83" "-undefined" "ARG84" "-unexported_symbols_list" "ARG85" "-weak_reference_mismatches" "ARG87" "-X" "-y" "-w" "-pagezero_size" "ARG54" "-segs_read_FOO" "-seglinkedit" "-noseglinkedit" "-sectalign" "ARG57_0" "ARG57_1" "ARG57_2" "-sectobjectsymbols" "ARG59_0" "ARG59_1" "-segcreate" "ARG65_0" "ARG65_1" "ARG65_2" "-whyload" "-whatsloaded" "-dylinker_install_name" "ARG16" "-dylinker" "-Mach" "-d" "-s" "-t" "-Z" "-u" "ARG82" "-undefined" "ARG84" "-A" "ARG0" "-e" "ARG19" "-m" "ARG33" "-r" "-o" "a.out" "-LARG2" "-lgomp".* "-filelist" "FOO" "-lFOO" "-allow_stack_execute" ".*/libprofile_rt.a" "-T" "ARG4" "-FARG1"}}
+// SPLATTER: {{".*ld.*" "-static" "-dylib" "-dylib_compatibility_version" "ARG11" "-dylib_current_version" "ARG12" "-arch" "i386" "-dylib_install_name" "ARG31" "-all_load" "-allowable_client" "ARG8" "-bind_at_load" "-dead_strip" "-no_dead_strip_inits_and_terms" "-dylib_file" "ARG14" "-dynamic" "-exported_symbols_list" "ARG20" "-flat_namespace" "-force_load" "ARG28" "-headerpad_max_install_names" "-image_base" "ARG29" "-init" "ARG30" "-macosx_version_min" "10.3.2" "-nomultidefs" "-multi_module" "-single_module" "-multiply_defined" "ARG37" "-multiply_defined_unused" "ARG38" "-pie" "-prebind" "-noprebind" "-nofixprebinding" "-prebind_all_twolevel_modules" "-read_only_relocs" "ARG55" "-sectcreate" "ARG58_0" "ARG58_1" "ARG58_2" "-sectorder" "ARG60_0" "ARG60_1" "ARG60_2" "-seg1addr" "ARG61" "-segprot" "ARG67_0" "ARG67_1" "ARG67_2" "-segaddr" "ARG64_0" "ARG64_1" "-segs_read_only_addr" "ARG69" "-segs_read_write_addr" "ARG70" "-seg_addr_table" "ARG62" "-seg_addr_table_filename" "ARG63" "-sub_library" "ARG77" "-sub_umbrella" "ARG78" "-twolevel_namespace" "-twolevel_namespace_hints" "-umbrella" "ARG83" "-undefined" "ARG84" "-unexported_symbols_list" "ARG85" "-weak_reference_mismatches" "ARG87" "-X" "-y" "-w" "-pagezero_size" "ARG54" "-segs_read_FOO" "-seglinkedit" "-noseglinkedit" "-sectalign" "ARG57_0" "ARG57_1" "ARG57_2" "-sectobjectsymbols" "ARG59_0" "ARG59_1" "-segcreate" "ARG65_0" "ARG65_1" "ARG65_2" "-whyload" "-whatsloaded" "-dylinker_install_name" "ARG16" "-dylinker" "-Mach" "-d" "-s" "-t" "-Z" "-u" "ARG82" "-undefined" "ARG84" "-A" "ARG0" "-e" "ARG19" "-m" "ARG33" "-r" "-o" "a.out" "-LARG2" "-lgomp".* "-filelist" "FOO" "-lFOO" "-allow_stack_execute" ".*/libprofile_rt.*" "-T" "ARG4" "-FARG1"}}
// Check linker changes that came with new linkedit format.
// RUN: touch %t.o
@@ -92,3 +92,19 @@
// LINK_OLDER_NODEMANGLE: {{ld(.exe)?"}}
// LINK_OLDER_NODEMANGLE-NOT: "-demangle"
// LINK_OLDER_NODEMANGLE: "-lSystem"
+
+// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -### %t.o \
+// RUN: -mlinker-version=117 -flto 2> %t.log
+// RUN: cat %t.log
+// RUN: FileCheck -check-prefix=LINK_OBJECT_LTO_PATH %s < %t.log
+//
+// LINK_OBJECT_LTO_PATH: {{ld(.exe)?"}}
+// LINK_OBJECT_LTO_PATH: "-object_path_lto"
+
+// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -### %t.o \
+// RUN: -force_load a -force_load b 2> %t.log
+// RUN: cat %t.log
+// RUN: FileCheck -check-prefix=FORCE_LOAD %s < %t.log
+//
+// FORCE_LOAD: {{ld(.exe)?"}}
+// FORCE_LOAD: "-force_load" "a" "-force_load" "b"
diff --git a/test/Driver/darwin-objc-options.m b/test/Driver/darwin-objc-options.m
index bc0b12cf55b0..50daa72333e8 100644
--- a/test/Driver/darwin-objc-options.m
+++ b/test/Driver/darwin-objc-options.m
@@ -15,5 +15,7 @@
// CHECK-CHECK-I386_ABI2: "-cc1"
// CHECK-CHECK-I386_ABI2: -fobjc-nonfragile-abi
+// CHECK-CHECK-I386_ABI2: -fobjc-exceptions
+// CHECK-CHECK-I386_ABI2: -fexceptions
// CHECK-CHECK-I386_ABI2-NOT: -fobjc-dispatch-method
// CHECK-CHECK-I386_ABI2: darwin-objc-options
diff --git a/test/Driver/darwin-xarch.c b/test/Driver/darwin-xarch.c
index d16d5318f7f8..4c6689cef0fc 100644
--- a/test/Driver/darwin-xarch.c
+++ b/test/Driver/darwin-xarch.c
@@ -12,3 +12,9 @@
// RUN: FileCheck --check-prefix=CHECK-LINK < %t %s
//
// CHECK-LINK: ld{{.*}} "-arch" "i386"{{.*}} "-some-linker-arg"
+
+// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -### \
+// RUN: -arch armv7 -Xarch_armv7 -Wl,-some-linker-arg -filelist X 2> %t
+// RUN: FileCheck --check-prefix=CHECK-ARMV7-LINK < %t %s
+//
+// CHECK-ARMV7-LINK: ld{{.*}} "-arch" "armv7"{{.*}} "-some-linker-arg"
diff --git a/test/Driver/gnu-runtime.m b/test/Driver/gnu-runtime.m
new file mode 100644
index 000000000000..5a3654c8c412
--- /dev/null
+++ b/test/Driver/gnu-runtime.m
@@ -0,0 +1,5 @@
+// RUN: %clang -ccc-host-triple i386-apple-darwin10 -### -fsyntax-only -fgnu-runtime %s 2>&1 | FileCheck %s
+// RUN: %clang -ccc-host-triple i386-apple-darwin10 -### -x objective-c++ -fsyntax-only -fgnu-runtime %s 2>&1 | FileCheck %s
+// CHECK: -fgnu-runtime
+// CHECK: -fobjc-runtime-has-arc
+// CHECK: -fobjc-runtime-has-weak
diff --git a/test/Driver/ios-simulator-arcruntime.c b/test/Driver/ios-simulator-arcruntime.c
new file mode 100644
index 000000000000..bec9f7b1fdc8
--- /dev/null
+++ b/test/Driver/ios-simulator-arcruntime.c
@@ -0,0 +1,6 @@
+// RUN: %clang -### -x objective-c -ccc-host-triple i386-apple-darwin10 -arch i386 -mmacosx-version-min=10.6 -D__IPHONE_OS_VERSION_MIN_REQUIRED=40201 -fobjc-arc -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-OPTIONS1 %s
+// RUN: %clang -### -x objective-c -ccc-host-triple i386-apple-darwin10 -arch i386 -mmacosx-version-min=10.6 -D__IPHONE_OS_VERSION_MIN_REQUIRED=50000 -fobjc-arc -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-OPTIONS2 %s
+//
+
+// CHECK-OPTIONS1-NOT: -fobjc-runtime-has-weak
+// CHECK-OPTIONS2: -fobjc-runtime-has-weak
diff --git a/test/Driver/mg.c b/test/Driver/mg.c
new file mode 100644
index 000000000000..4f438142f411
--- /dev/null
+++ b/test/Driver/mg.c
@@ -0,0 +1,5 @@
+// RUN: %clang -M -MG -include nonexistent-preinclude.h %s > %t
+// RUN: fgrep nonexistent-preinclude.h %t
+// RUN: fgrep nonexistent-ppinclude.h %t
+
+#include "nonexistent-ppinclude.h"
diff --git a/test/Driver/no-objc-arr.m b/test/Driver/no-objc-arr.m
new file mode 100644
index 000000000000..15fbdc20ce8a
--- /dev/null
+++ b/test/Driver/no-objc-arr.m
@@ -0,0 +1,8 @@
+// RUN: %clang -Werror -fobjc-arc -fsyntax-only -fno-objc-arc -verify %s
+// rdar://8949617
+
+void * FOO() {
+ id string = @"Hello World.\n";
+ void *pointer = string; // No error must be issued
+ return pointer;
+}
diff --git a/test/Driver/noexecstack.c b/test/Driver/noexecstack.c
new file mode 100644
index 000000000000..1f4772882654
--- /dev/null
+++ b/test/Driver/noexecstack.c
@@ -0,0 +1 @@
+// RUN: %clang -### %s -c -o tmp.o -triple i686-pc-linux-gnu -integrated-as -Wa,--noexecstack 2>&1 | grep "mnoexecstack"
diff --git a/test/Driver/rewrite-objc.m b/test/Driver/rewrite-objc.m
index 2fe2ccec6a7c..c47b52334c91 100644
--- a/test/Driver/rewrite-objc.m
+++ b/test/Driver/rewrite-objc.m
@@ -3,7 +3,7 @@
// TEST0: clang{{.*}}" "-cc1"
// TEST0: "-rewrite-objc"
// FIXME: CHECK-NOT is broken somehow, it doesn't work here. Check adjacency instead.
-// TEST0: "-fmessage-length" "0" "-fobjc-infer-related-result-type" "-fobjc-exceptions" "-fdiagnostics-show-option"
+// TEST0: "-fmessage-length" "0" "-fno-objc-infer-related-result-type" "-fobjc-exceptions" "-fdiagnostics-show-option"
// TEST0: rewrite-objc.m"
// RUN: not %clang -ccc-no-clang -ccc-host-triple unknown -rewrite-objc %s -o - -### 2>&1 | \
diff --git a/test/Driver/sysroot.c b/test/Driver/sysroot.c
index 34f31001acc8..79db900d07e2 100644
--- a/test/Driver/sysroot.c
+++ b/test/Driver/sysroot.c
@@ -1,18 +1,18 @@
// Check that --sysroot= also applies to header search paths.
// RUN: %clang -ccc-host-triple i386-unk-unk --sysroot=/FOO -### -E %s 2> %t1
// RUN: FileCheck --check-prefix=CHECK-SYSROOTEQ < %t1 %s
-// CHECK-SYSROOTEQ: "-cc1"{{.*}} "-isysroot" "/FOO"
+// CHECK-SYSROOTEQ: "-cc1"{{.*}} "-isysroot" "{{[^"]*}}/FOO"
// Apple Darwin uses -isysroot as the syslib root, too.
// RUN: touch %t2.o
// RUN: %clang -ccc-host-triple i386-apple-darwin10 \
// RUN: -isysroot /FOO -### %t2.o 2> %t2
// RUN: FileCheck --check-prefix=CHECK-APPLE-ISYSROOT < %t2 %s
-// CHECK-APPLE-ISYSROOT: "-arch" "i386"{{.*}} "-syslibroot" "/FOO"
+// CHECK-APPLE-ISYSROOT: "-arch" "i386"{{.*}} "-syslibroot" "{{[^"]*}}/FOO"
// Check that honor --sysroot= over -isysroot, for Apple Darwin.
// RUN: touch %t3.o
// RUN: %clang -ccc-host-triple i386-apple-darwin10 \
// RUN: -isysroot /FOO --sysroot=/BAR -### %t3.o 2> %t3
// RUN: FileCheck --check-prefix=CHECK-APPLE-SYSROOT < %t3 %s
-// CHECK-APPLE-SYSROOT: "-arch" "i386"{{.*}} "-syslibroot" "/BAR"
+// CHECK-APPLE-SYSROOT: "-arch" "i386"{{.*}} "-syslibroot" "{{[^"]*}}/BAR"
diff --git a/test/Driver/x86_features.c b/test/Driver/x86_features.c
index 9dbdd0ae90b4..0db372ec64f1 100644
--- a/test/Driver/x86_features.c
+++ b/test/Driver/x86_features.c
@@ -1,3 +1,3 @@
// RUN: %clang -ccc-host-triple i386-unknown-unknown -### -S %s -msse -msse4 -mno-sse -mno-mmx -msse 2> %t
-// RUN: grep '"-target-feature" "+sse" "-target-feature" "+sse4" "-target-feature" "-sse" "-target-feature" "-mmx" "-target-feature" "+sse"' %t
-
+// RUN: grep '"pentium4" "-target-feature" "+sse4" "-target-feature" "-mmx" "-target-feature" "+sse"' %t
+// Note that we filter out all but the last -m(no)sse.
diff --git a/test/FixIt/fixit-objc.m b/test/FixIt/fixit-objc.m
index bf704c66a027..2e8bfaea6aa3 100644
--- a/test/FixIt/fixit-objc.m
+++ b/test/FixIt/fixit-objc.m
@@ -39,3 +39,17 @@ void f(Test *t) {
[t test:@"Foo"]]; // expected-error{{extraneous ']' before ';'}}
g(@"Foo")); // expected-error{{extraneous ')' before ';'}}
}
+
+// rdar://7861841
+@interface Radar7861841 {
+@public
+ int x;
+}
+
+@property (assign) int y;
+@end
+
+int f0(Radar7861841 *a) { return a.x; } // expected-error {{property 'x' not found on object of type 'Radar7861841 *'; did you mean to access ivar 'x'}}
+
+int f1(Radar7861841 *a) { return a->y; } // expected-error {{property 'y' found on object of type 'Radar7861841 *'; did you mean to access it with the "." operator?}}
+
diff --git a/test/FixIt/fixit.c b/test/FixIt/fixit.c
index 1a6ef635570a..ba45cf28e694 100644
--- a/test/FixIt/fixit.c
+++ b/test/FixIt/fixit.c
@@ -33,9 +33,14 @@ void f1(x, y)
int i0 = { 17 };
+#define ONE 1
+#define TWO 2
+
int test_cond(int y, int fooBar) {
// CHECK: int x = y ? 1 : 4+fooBar;
int x = y ? 1 4+foobar;
+// CHECK: x = y ? ONE : TWO;
+ x = y ? ONE TWO;
return x;
}
diff --git a/test/FixIt/typo-crash.cpp b/test/FixIt/typo-crash.cpp
new file mode 100644
index 000000000000..b156e1b44c45
--- /dev/null
+++ b/test/FixIt/typo-crash.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// FIXME: The diagnostics and recovery here are very, very poor.
+
+// PR10355
+template<typename T> void template_id1() {
+ template_id2<> t; // expected-error 2{{use of undeclared identifier 'template_id2'; did you mean 'template_id1'?}} \
+ // expected-error{{expected expression}} \
+ // expected-error{{use of undeclared identifier 't'}}
+ }
+
diff --git a/test/FixIt/typo.cpp b/test/FixIt/typo.cpp
index f8b5352374f3..3d40da8d256a 100644
--- a/test/FixIt/typo.cpp
+++ b/test/FixIt/typo.cpp
@@ -74,3 +74,15 @@ int foo() {
unsinged *ptr = 0; // expected-error{{use of undeclared identifier 'unsinged'; did you mean 'unsigned'?}}
return *i + *ptr + global_val; // expected-error{{use of undeclared identifier 'global_val'; did you mean 'global_value'?}}
}
+
+namespace nonstd {
+ typedef std::basic_string<char> yarn; // expected-note{{'nonstd::yarn' declared here}}
+}
+
+yarn str4; // expected-error{{unknown type name 'yarn'; did you mean 'nonstd::yarn'?}}
+
+namespace check_bool {
+ void f() {
+ Bool b; // expected-error{{use of undeclared identifier 'Bool'; did you mean 'bool'?}}
+ }
+}
diff --git a/test/Frontend/dependency-gen.c b/test/Frontend/dependency-gen.c
index 0f8adabc85aa..49d3f28614c5 100644
--- a/test/Frontend/dependency-gen.c
+++ b/test/Frontend/dependency-gen.c
@@ -1,19 +1,27 @@
-// rdar://6533411
-// RUN: %clang -MD -MF %t.d -S -x c -o %t.o %s
-// RUN: grep '.*dependency-gen.*:' %t.d
-// RUN: grep 'dependency-gen.c' %t.d
-
-// RUN: %clang -S -M -x c %s -o %t.d
-// RUN: grep '.*dependency-gen.*:' %t.d
-// RUN: grep 'dependency-gen.c' %t.d
-
-// PR8974
// REQUIRES: shell
-// "cd %t.dir" requires shell.
+// Basic test
// RUN: rm -rf %t.dir
// RUN: mkdir -p %t.dir/a/b
// RUN: echo > %t.dir/a/b/x.h
// RUN: cd %t.dir
-// RUN: %clang -include a/b/x.h -MD -MF %t.d -S -x c -o %t.o %s
-// RUN: grep ' a/b/x\.h' %t.d
+// RUN: %clang -MD -MF - %s -fsyntax-only -I a/b | FileCheck -check-prefix=CHECK-ONE %s
+// CHECK-ONE: {{ }}a/b/x.h
+
+// PR8974 (-include flag)
+// RUN: %clang -MD -MF - %s -fsyntax-only -include a/b/x.h -DINCLUDE_FLAG_TEST | FileCheck -check-prefix=CHECK-TWO %s
+// CHECK-TWO: {{ }}a/b/x.h
+
+// rdar://problem/9734352 (paths involving ".")
+// RUN: %clang -MD -MF - %s -fsyntax-only -I ./a/b | FileCheck -check-prefix=CHECK-THREE %s
+// CHECK-THREE: {{ }}a/b/x.h
+// RUN: %clang -MD -MF - %s -fsyntax-only -I .//./a/b/ | FileCheck -check-prefix=CHECK-FOUR %s
+// CHECK-FOUR: {{ }}a/b/x.h
+// RUN: %clang -MD -MF - %s -fsyntax-only -I a/b/. | FileCheck -check-prefix=CHECK-FIVE %s
+// CHECK-FIVE: {{ }}a/b/./x.h
+// RUN: cd a/b
+// RUN: %clang -MD -MF - %s -fsyntax-only -I ./ | FileCheck -check-prefix=CHECK-SIX %s
+// CHECK-SIX: {{ }}x.h
+#ifndef INCLUDE_FLAG_TEST
+#include <x.h>
+#endif
diff --git a/test/Index/annotate-tokens-pp.c b/test/Index/annotate-tokens-pp.c
index 01a615f0e4cb..e6bb0869d0b1 100644
--- a/test/Index/annotate-tokens-pp.c
+++ b/test/Index/annotate-tokens-pp.c
@@ -53,14 +53,14 @@ void test() {
// CHECK: Identifier: "X" [4:22 - 4:23] macro definition=WIBBLE
// CHECK: Punctuation: "##" [4:23 - 4:25] macro definition=WIBBLE
// CHECK: Identifier: "Y" [4:25 - 4:26] macro definition=WIBBLE
-// CHECK: Identifier: "NOTHING" [5:1 - 5:8] macro instantiation=NOTHING:1:9
+// CHECK: Identifier: "NOTHING" [5:1 - 5:8] macro expansion=NOTHING:1:9
// CHECK: Punctuation: "(" [5:8 - 5:9]
// CHECK: Identifier: "more" [5:9 - 5:13]
// CHECK: Punctuation: "," [5:13 - 5:14]
// CHECK: Identifier: "junk" [5:14 - 5:18]
// CHECK: Punctuation: ")" [5:18 - 5:19]
// CHECK: Keyword: "float" [5:20 - 5:25]
-// CHECK: Identifier: "WIBBLE" [5:26 - 5:32] macro instantiation=WIBBLE:4:9
+// CHECK: Identifier: "WIBBLE" [5:26 - 5:32] macro expansion=WIBBLE:4:9
// CHECK: Punctuation: "(" [5:32 - 5:33]
// CHECK: Keyword: "int" [5:33 - 5:36]
// CHECK: Punctuation: "," [5:36 - 5:37]
@@ -68,8 +68,8 @@ void test() {
// CHECK: Punctuation: ")" [5:43 - 5:44]
// CHECK: Punctuation: ";" [5:44 - 5:45]
// CHECK: Keyword: "int" [6:1 - 6:4]
-// CHECK: Identifier: "BAR" [6:5 - 6:8] macro instantiation=BAR:3:9
-// CHECK: Identifier: "STILL_NOTHING" [6:9 - 6:22] macro instantiation=STILL_NOTHING:2:9
+// CHECK: Identifier: "BAR" [6:5 - 6:8] macro expansion=BAR:3:9
+// CHECK: Identifier: "STILL_NOTHING" [6:9 - 6:22] macro expansion=STILL_NOTHING:2:9
// CHECK: Punctuation: ";" [6:22 - 6:23]
// CHECK: Punctuation: "#" [7:1 - 7:2] inclusion directive=foo.h
// CHECK: Identifier: "include" [7:2 - 7:9] inclusion directive=foo.h
@@ -115,7 +115,7 @@ void test() {
// CHECK: Keyword: "int" [16:3 - 16:6] VarDecl=k:16:7 (Definition)
// CHECK: Identifier: "k" [16:7 - 16:8] VarDecl=k:16:7 (Definition)
// CHECK: Punctuation: "=" [16:9 - 16:10] VarDecl=k:16:7 (Definition)
-// CHECK: Identifier: "REVERSE_MACRO" [16:11 - 16:24] macro instantiation=REVERSE_MACRO:10:9
+// CHECK: Identifier: "REVERSE_MACRO" [16:11 - 16:24] macro expansion=REVERSE_MACRO:10:9
// CHECK: Punctuation: "(" [16:24 - 16:25] UnexposedStmt=
// CHECK: Identifier: "t" [16:25 - 16:26] DeclRefExpr=t:15:7
// CHECK: Punctuation: "," [16:26 - 16:27] UnexposedStmt=
@@ -125,7 +125,7 @@ void test() {
// CHECK: Keyword: "int" [17:3 - 17:6] VarDecl=j:17:7 (Definition)
// CHECK: Identifier: "j" [17:7 - 17:8] VarDecl=j:17:7 (Definition)
// CHECK: Punctuation: "=" [17:9 - 17:10] VarDecl=j:17:7 (Definition)
-// CHECK: Identifier: "TWICE_MACRO" [17:11 - 17:22] macro instantiation=TWICE_MACRO:11:9
+// CHECK: Identifier: "TWICE_MACRO" [17:11 - 17:22] macro expansion=TWICE_MACRO:11:9
// CHECK: Punctuation: "(" [17:22 - 17:23] UnexposedStmt=
// CHECK: Identifier: "k" [17:23 - 17:24] DeclRefExpr=k:16:7
// CHECK: Punctuation: "+" [17:25 - 17:26] UnexposedStmt=
@@ -170,7 +170,7 @@ void test() {
// CHECK: Punctuation: "=" [24:9 - 24:10] VarDecl=x:24:7 (Definition)
// CHECK: Literal: "10" [24:11 - 24:13] UnexposedExpr=
// CHECK: Punctuation: ";" [24:13 - 24:14] UnexposedStmt=
-// CHECK: Identifier: "fun_with_macro_bodies" [25:3 - 25:24] macro instantiation=fun_with_macro_bodies:21:9
+// CHECK: Identifier: "fun_with_macro_bodies" [25:3 - 25:24] macro expansion=fun_with_macro_bodies:21:9
// CHECK: Punctuation: "(" [25:24 - 25:25] UnexposedStmt=
// CHECK: Identifier: "x" [25:25 - 25:26] DeclRefExpr=x:24:7
// CHECK: Punctuation: "," [25:26 - 25:27] UnexposedStmt=
diff --git a/test/Index/annotate-tokens.cpp b/test/Index/annotate-tokens.cpp
index ccc9e9602843..165420ab39ce 100644
--- a/test/Index/annotate-tokens.cpp
+++ b/test/Index/annotate-tokens.cpp
@@ -17,9 +17,10 @@ struct S1 { void f(); };
struct S2 { S1 *operator->(); };
void test3(S2 s2) {
s2->f();
+ X foo;
}
-// RUN: c-index-test -test-annotate-tokens=%s:1:1:20:1 %s | FileCheck %s
+// RUN: c-index-test -test-annotate-tokens=%s:1:1:21:1 %s | FileCheck %s
// CHECK: Keyword: "struct" [1:1 - 1:7] StructDecl=bonk:1:8 (Definition)
// CHECK: Identifier: "bonk" [1:8 - 1:12] StructDecl=bonk:1:8 (Definition)
// CHECK: Punctuation: "{" [1:13 - 1:14] StructDecl=bonk:1:8 (Definition)
@@ -115,4 +116,7 @@ void test3(S2 s2) {
// CHECK: Punctuation: "(" [19:8 - 19:9] CallExpr=f:16:18
// CHECK: Punctuation: ")" [19:9 - 19:10] CallExpr=f:16:18
// CHECK: Punctuation: ";" [19:10 - 19:11] UnexposedStmt=
-// CHECK: Punctuation: "}" [20:1 - 20:2] UnexposedStmt=
+// CHECK: Identifier: "X" [20:3 - 20:4] TypeRef=struct X:7:8
+// CHECK: Identifier: "foo" [20:5 - 20:8] VarDecl=foo:20:5 (Definition)
+// CHECK: Punctuation: ";" [20:8 - 20:9] UnexposedStmt=
+// CHECK: Punctuation: "}" [21:1 - 21:2] UnexposedStmt=
diff --git a/test/Index/annotate-tokens.m b/test/Index/annotate-tokens.m
index 1eb77940da2e..1dc762123207 100644
--- a/test/Index/annotate-tokens.m
+++ b/test/Index/annotate-tokens.m
@@ -134,6 +134,7 @@ static Rdar8595462_A * Rdar8595462_staticVar;
@interface Rdar8062781
+ (Foo*)getB;
@property (readonly, nonatomic) Foo *blah;
+@property (readonly, atomic) Foo *abah;
@end
// RUN: c-index-test -test-annotate-tokens=%s:1:1:118:1 %s -DIBOutlet='__attribute__((iboutlet))' -DIBAction='void)__attribute__((ibaction)' | FileCheck %s
@@ -226,7 +227,7 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK: Identifier: "IBActionTests" [32:12 - 32:25] ObjCInterfaceDecl=IBActionTests:32:12
// CHECK: Punctuation: "-" [33:1 - 33:2] ObjCInstanceMethodDecl=actionMethod::33:1
// CHECK: Punctuation: "(" [33:3 - 33:4] ObjCInstanceMethodDecl=actionMethod::33:1
-// CHECK: Identifier: "IBAction" [33:4 - 33:12] macro instantiation=IBAction
+// CHECK: Identifier: "IBAction" [33:4 - 33:12] macro expansion=IBAction
// CHECK: Punctuation: ")" [33:12 - 33:13] ObjCInstanceMethodDecl=actionMethod::33:1
// CHECK: Identifier: "actionMethod" [33:14 - 33:26] ObjCInstanceMethodDecl=actionMethod::33:1
// CHECK: Punctuation: ":" [33:26 - 33:27] ObjCInstanceMethodDecl=actionMethod::33:1
@@ -261,7 +262,7 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK: Identifier: "IBActionTests" [37:17 - 37:30] ObjCImplementationDecl=IBActionTests:37:1 (Definition)
// CHECK: Punctuation: "-" [38:1 - 38:2] ObjCInstanceMethodDecl=actionMethod::38:1 (Definition)
// CHECK: Punctuation: "(" [38:3 - 38:4] ObjCInstanceMethodDecl=actionMethod::38:1 (Definition)
-// CHECK: Identifier: "IBAction" [38:4 - 38:12] macro instantiation=IBAction
+// CHECK: Identifier: "IBAction" [38:4 - 38:12] macro expansion=IBAction
// CHECK: Punctuation: ")" [38:12 - 38:13] ObjCInstanceMethodDecl=actionMethod::38:1 (Definition)
// CHECK: Identifier: "actionMethod" [38:14 - 38:26] ObjCInstanceMethodDecl=actionMethod::38:1 (Definition)
// CHECK: Punctuation: ":" [38:26 - 38:27] ObjCInstanceMethodDecl=actionMethod::38:1 (Definition)
@@ -305,7 +306,7 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK: Keyword: "interface" [51:2 - 51:11] ObjCInterfaceDecl=IBOutletTests:51:12
// CHECK: Identifier: "IBOutletTests" [51:12 - 51:25] ObjCInterfaceDecl=IBOutletTests:51:12
// CHECK: Punctuation: "{" [52:1 - 52:2] ObjCInterfaceDecl=IBOutletTests:51:12
-// CHECK: Identifier: "IBOutlet" [53:5 - 53:13] macro instantiation=IBOutlet
+// CHECK: Identifier: "IBOutlet" [53:5 - 53:13] macro expansion=IBOutlet
// CHECK: Keyword: "char" [53:14 - 53:18] ObjCIvarDecl=anOutlet:53:21 (Definition)
// CHECK: Punctuation: "*" [53:19 - 53:20] ObjCIvarDecl=anOutlet:53:21 (Definition)
// CHECK: Identifier: "anOutlet" [53:21 - 53:29] ObjCIvarDecl=anOutlet:53:21 (Definition)
@@ -313,7 +314,7 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK: Punctuation: "}" [54:1 - 54:2] ObjCInterfaceDecl=IBOutletTests:51:12
// CHECK: Punctuation: "-" [55:1 - 55:2] ObjCInstanceMethodDecl=actionMethod::55:1
// CHECK: Punctuation: "(" [55:3 - 55:4] ObjCInstanceMethodDecl=actionMethod::55:1
-// CHECK: Identifier: "IBAction" [55:4 - 55:12] macro instantiation=IBAction
+// CHECK: Identifier: "IBAction" [55:4 - 55:12] macro expansion=IBAction
// CHECK: Punctuation: ")" [55:12 - 55:13] ObjCInstanceMethodDecl=actionMethod::55:1
// CHECK: Identifier: "actionMethod" [55:14 - 55:26] ObjCInstanceMethodDecl=actionMethod::55:1
// CHECK: Punctuation: ":" [55:26 - 55:27] ObjCInstanceMethodDecl=actionMethod::55:1
@@ -324,7 +325,7 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK: Punctuation: ";" [55:34 - 55:35] ObjCInstanceMethodDecl=actionMethod::55:1
// CHECK: Punctuation: "@" [56:1 - 56:2] ObjCPropertyDecl=aPropOutlet:56:26
// CHECK: Keyword: "property" [56:2 - 56:10] ObjCPropertyDecl=aPropOutlet:56:26
-// CHECK: Identifier: "IBOutlet" [56:11 - 56:19] macro instantiation=IBOutlet
+// CHECK: Identifier: "IBOutlet" [56:11 - 56:19] macro expansion=IBOutlet
// CHECK: Keyword: "int" [56:20 - 56:23] ObjCPropertyDecl=aPropOutlet:56:26
// CHECK: Punctuation: "*" [56:24 - 56:25] ObjCPropertyDecl=aPropOutlet:56:26
// CHECK: Identifier: "aPropOutlet" [56:26 - 56:37] ObjCPropertyDecl=aPropOutlet:56:26
@@ -388,7 +389,7 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK: Identifier: "self" [76:18 - 76:22] DeclRefExpr=self:0:0
// CHECK: Identifier: "foo" [76:23 - 76:26] ObjCMessageExpr=foo::66:1
// CHECK: Punctuation: ":" [76:26 - 76:27] ObjCMessageExpr=foo::66:1
-// CHECK: Identifier: "VAL" [76:27 - 76:30] macro instantiation=VAL:63:9
+// CHECK: Identifier: "VAL" [76:27 - 76:30] macro expansion=VAL:63:9
// CHECK: Punctuation: "]" [76:30 - 76:31] ObjCMessageExpr=foo::66:1
// CHECK: Punctuation: ";" [76:31 - 76:32] UnexposedStmt=
// CHECK: Keyword: "int" [77:5 - 77:8] VarDecl=second:77:9 (Definition)
@@ -526,7 +527,7 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK-INSIDE_BLOCK: Punctuation: "=" [128:20 - 128:21] VarDecl=a:128:18 (Definition)
// CHECK-INSIDE_BLOCK: Identifier: "self" [128:22 - 128:26] DeclRefExpr=self:0:0
-// RUN: c-index-test -test-annotate-tokens=%s:134:1:137:1 %s -DIBOutlet='__attribute__((iboutlet))' -DIBAction='void)__attribute__((ibaction)' | FileCheck -check-prefix=CHECK-PROP-AFTER-METHOD %s
+// RUN: c-index-test -test-annotate-tokens=%s:134:1:138:1 %s -DIBOutlet='__attribute__((iboutlet))' -DIBAction='void)__attribute__((ibaction)' | FileCheck -check-prefix=CHECK-PROP-AFTER-METHOD %s
// CHECK-PROP-AFTER-METHOD: Punctuation: "@" [134:1 - 134:2] ObjCInterfaceDecl=Rdar8062781:134:12
// CHECK-PROP-AFTER-METHOD: Keyword: "interface" [134:2 - 134:11] ObjCInterfaceDecl=Rdar8062781:134:12
// CHECK-PROP-AFTER-METHOD: Identifier: "Rdar8062781" [134:12 - 134:23] ObjCInterfaceDecl=Rdar8062781:134:12
@@ -548,4 +549,15 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK-PROP-AFTER-METHOD: Punctuation: "*" [136:37 - 136:38] ObjCPropertyDecl=blah:136:38
// CHECK-PROP-AFTER-METHOD: Identifier: "blah" [136:38 - 136:42] ObjCPropertyDecl=blah:136:38
// CHECK-PROP-AFTER-METHOD: Punctuation: ";" [136:42 - 136:43] ObjCInterfaceDecl=Rdar8062781:134:12
-// CHECK-PROP-AFTER-METHOD: Punctuation: "@" [137:1 - 137:2] ObjCInterfaceDecl=Rdar8062781:134:12
+// CHECK-PROP-AFTER-METHOD: Punctuation: "@" [137:1 - 137:2] ObjCPropertyDecl=abah:137:35
+// CHECK-PROP-AFTER-METHOD: Keyword: "property" [137:2 - 137:10] ObjCPropertyDecl=abah:137:35
+// CHECK-PROP-AFTER-METHOD: Punctuation: "(" [137:11 - 137:12] ObjCPropertyDecl=abah:137:35
+// CHECK-PROP-AFTER-METHOD: Keyword: "readonly" [137:12 - 137:20] ObjCPropertyDecl=abah:137:35
+// CHECK-PROP-AFTER-METHOD: Punctuation: "," [137:20 - 137:21] ObjCPropertyDecl=abah:137:35
+// CHECK-PROP-AFTER-METHOD: Keyword: "atomic" [137:22 - 137:28] ObjCPropertyDecl=abah:137:35
+// CHECK-PROP-AFTER-METHOD: Punctuation: ")" [137:28 - 137:29] ObjCPropertyDecl=abah:137:35
+// CHECK-PROP-AFTER-METHOD: Identifier: "Foo" [137:30 - 137:33] ObjCClassRef=Foo:1:12
+// CHECK-PROP-AFTER-METHOD: Punctuation: "*" [137:34 - 137:35] ObjCPropertyDecl=abah:137:35
+// CHECK-PROP-AFTER-METHOD: Identifier: "abah" [137:35 - 137:39] ObjCPropertyDecl=abah:137:35
+// CHECK-PROP-AFTER-METHOD: Punctuation: ";" [137:39 - 137:40] ObjCInterfaceDecl=Rdar8062781:134:12
+// CHECK-PROP-AFTER-METHOD: Punctuation: "@" [138:1 - 138:2] ObjCInterfaceDecl=Rdar8062781:134:12
diff --git a/test/Index/arc-annotate.m b/test/Index/arc-annotate.m
new file mode 100644
index 000000000000..b836bc8b26de
--- /dev/null
+++ b/test/Index/arc-annotate.m
@@ -0,0 +1,38 @@
+@interface A
+@property (strong, nonatomic) id property;
+@property (nonatomic, weak) id second_property;
+@property (unsafe_unretained, nonatomic) id third_property;
+@end
+
+// RUN: c-index-test -test-annotate-tokens=%s:1:1:5:1 %s -fobjc-arc -fobjc-nonfragile-abi | FileCheck %s
+// CHECK: Punctuation: "@" [1:1 - 1:2] ObjCInterfaceDecl=A:1:12
+// CHECK: Keyword: "interface" [1:2 - 1:11] ObjCInterfaceDecl=A:1:12
+// CHECK: Identifier: "A" [1:12 - 1:13] ObjCInterfaceDecl=A:1:12
+// CHECK: Punctuation: "@" [2:1 - 2:2] ObjCPropertyDecl=property:2:34
+// CHECK: Keyword: "property" [2:2 - 2:10] ObjCPropertyDecl=property:2:34
+// CHECK: Punctuation: "(" [2:11 - 2:12] ObjCPropertyDecl=property:2:34
+// CHECK: Keyword: "strong" [2:12 - 2:18] ObjCPropertyDecl=property:2:34
+// CHECK: Punctuation: "," [2:18 - 2:19] ObjCPropertyDecl=property:2:34
+// CHECK: Keyword: "nonatomic" [2:20 - 2:29] ObjCPropertyDecl=property:2:34
+// CHECK: Punctuation: ")" [2:29 - 2:30] ObjCPropertyDecl=property:2:34
+// CHECK: Identifier: "id" [2:31 - 2:33] TypeRef=id:0:0
+// CHECK: Identifier: "property" [2:34 - 2:42] ObjCPropertyDecl=property:2:34
+// CHECK: Punctuation: ";" [2:42 - 2:43] ObjCInterfaceDecl=A:1:12
+// CHECK: Punctuation: "@" [3:1 - 3:2] ObjCPropertyDecl=second_property:3:32
+// CHECK: Keyword: "property" [3:2 - 3:10] ObjCPropertyDecl=second_property:3:32
+// CHECK: Punctuation: "(" [3:11 - 3:12] ObjCPropertyDecl=second_property:3:32
+// CHECK: Keyword: "nonatomic" [3:12 - 3:21] ObjCPropertyDecl=second_property:3:32
+// CHECK: Punctuation: "," [3:21 - 3:22] ObjCPropertyDecl=second_property:3:32
+// CHECK: Keyword: "weak" [3:23 - 3:27] ObjCPropertyDecl=second_property:3:32
+// CHECK: Punctuation: ")" [3:27 - 3:28] ObjCPropertyDecl=second_property:3:32
+// CHECK: Identifier: "id" [3:29 - 3:31] TypeRef=id:0:0
+// CHECK: Identifier: "second_property" [3:32 - 3:47] ObjCPropertyDecl=second_property:3:32
+// CHECK: Punctuation: "@" [4:1 - 4:2] ObjCPropertyDecl=third_property:4:45
+// CHECK: Keyword: "property" [4:2 - 4:10] ObjCPropertyDecl=third_property:4:45
+// CHECK: Punctuation: "(" [4:11 - 4:12] ObjCPropertyDecl=third_property:4:45
+// CHECK: Keyword: "unsafe_unretained" [4:12 - 4:29] ObjCPropertyDecl=third_property:4:45
+// CHECK: Punctuation: "," [4:29 - 4:30] ObjCPropertyDecl=third_property:4:45
+// CHECK: Keyword: "nonatomic" [4:31 - 4:40] ObjCPropertyDecl=third_property:4:45
+// CHECK: Punctuation: ")" [4:40 - 4:41] ObjCPropertyDecl=third_property:4:45
+// CHECK: Identifier: "id" [4:42 - 4:44] TypeRef=id:0:0
+// CHECK: Identifier: "third_property" [4:45 - 4:59] ObjCPropertyDecl=third_property:4:45
diff --git a/test/Index/arc-complete.m b/test/Index/arc-complete.m
new file mode 100644
index 000000000000..328983c441ec
--- /dev/null
+++ b/test/Index/arc-complete.m
@@ -0,0 +1,16 @@
+typedef const void *CFTypeRef;
+
+void test(id x) {
+ (__bridge CFTypeRef)x;
+}
+
+
+
+// RUN: c-index-test -code-completion-at=%s:4:4 %s -fobjc-arc -fobjc-nonfragile-abi | FileCheck -check-prefix=CHECK-CC1 %s
+// CHECK-CC1: macro definition:{TypedText __autoreleasing} (70)
+// CHECK-CC1: NotImplemented:{TypedText __bridge}{HorizontalSpace }{Placeholder type}{RightParen )}{Placeholder expression} (40)
+// CHECK-CC1: NotImplemented:{TypedText __bridge_retained}{HorizontalSpace }{Placeholder CF type}{RightParen )}{Placeholder expression} (40)
+// CHECK-CC1: NotImplemented:{TypedText __bridge_transfer}{HorizontalSpace }{Placeholder Objective-C type}{RightParen )}{Placeholder expression} (40)
+// CHECK-CC1: macro definition:{TypedText __strong} (70)
+// CHECK-CC1: macro definition:{TypedText __unsafe_unretained} (70)
+// CHECK-CC1: macro definition:{TypedText __weak} (70)
diff --git a/test/Index/c-index-api-loadTU-test.m b/test/Index/c-index-api-loadTU-test.m
index 98a41d837fdc..ab5f9a9ed6f9 100644
--- a/test/Index/c-index-api-loadTU-test.m
+++ b/test/Index/c-index-api-loadTU-test.m
@@ -70,6 +70,11 @@ typedef struct X0 X1;
struct X0;
struct X0 {};
+@interface TestAttributes()
+// <rdar://problem/9561076>
+@property (retain) IBOutlet id anotherOutlet;
+@end
+
// CHECK: c-index-api-loadTU-test.m:4:12: ObjCInterfaceDecl=Foo:4:12 Extent=[4:1 - 12:5]
// CHECK: c-index-api-loadTU-test.m:6:32: ObjCIvarDecl=myoutlet:6:32 (Definition) Extent=[6:3 - 6:40]
// CHECK: <invalid loc>:0:0: attribute(iboutlet)=
@@ -150,3 +155,9 @@ struct X0 {};
// CHECK: c-index-api-loadTU-test.m:70:8: StructDecl=X0:70:8 Extent=[70:1 - 70:10]
// CHECK: c-index-api-loadTU-test.m:71:8: StructDecl=X0:71:8 (Definition) Extent=[71:1 - 71:14]
+// CHECK: <invalid loc>:0:0: attribute(iboutlet)=
+// CHECK: c-index-api-loadTU-test.m:75:29: TypeRef=id:0:0 Extent=[75:29 - 75:31]
+// CHECK: c-index-api-loadTU-test.m:75:32: ObjCInstanceMethodDecl=anotherOutlet:75:32 Extent=[75:32 - 75:45]
+// CHECK: c-index-api-loadTU-test.m:75:32: ObjCInstanceMethodDecl=setAnotherOutlet::75:32 Extent=[75:32 - 75:45]
+// CHECK: c-index-api-loadTU-test.m:75:32: ParmDecl=anotherOutlet:75:32 (Definition) Extent=[75:32 - 75:45]
+
diff --git a/test/Index/c-index-getCursor-pp.c b/test/Index/c-index-getCursor-pp.c
index 8f986912cd6b..df61ec0329e5 100644
--- a/test/Index/c-index-getCursor-pp.c
+++ b/test/Index/c-index-getCursor-pp.c
@@ -18,15 +18,15 @@ B(int x);
// RUN: c-index-test -cursor-at=%s:2:14 -I%S/Inputs %s | FileCheck -check-prefix=CHECK-2 %s
// CHECK-2: macro definition=DECORATION
// RUN: c-index-test -cursor-at=%s:5:7 -I%S/Inputs %s | FileCheck -check-prefix=CHECK-3 %s
-// CHECK-3: macro instantiation=OBSCURE:1:9
+// CHECK-3: macro expansion=OBSCURE:1:9
// RUN: c-index-test -cursor-at=%s:6:6 -I%S/Inputs %s | FileCheck -check-prefix=CHECK-4 %s
-// CHECK-4: macro instantiation=OBSCURE:1:9
+// CHECK-4: macro expansion=OBSCURE:1:9
// RUN: c-index-test -cursor-at=%s:6:19 -I%S/Inputs %s | FileCheck -check-prefix=CHECK-5 %s
-// CHECK-5: macro instantiation=DECORATION:2:9
+// CHECK-5: macro expansion=DECORATION:2:9
// RUN: c-index-test -cursor-at=%s:9:10 -I%S/Inputs %s | FileCheck -check-prefix=CHECK-6 %s
// CHECK-6: inclusion directive=a.h
// RUN: c-index-test -cursor-at=%s:14:1 -I%S/Inputs %s | FileCheck -check-prefix=CHECK-7 %s
-// CHECK-7: macro instantiation=B:12:9
+// CHECK-7: macro expansion=B:12:9
// Same tests, but with "editing" optimizations
// RUN: env CINDEXTEST_EDITING=1 c-index-test -cursor-at=%s:1:11 -I%S/Inputs %s | FileCheck -check-prefix=CHECK-1 %s
diff --git a/test/Index/c-index-getCursor-test.m b/test/Index/c-index-getCursor-test.m
index c2ff6963c9ff..6df8c1abfeed 100644
--- a/test/Index/c-index-getCursor-test.m
+++ b/test/Index/c-index-getCursor-test.m
@@ -165,4 +165,4 @@ void f() {
// CHECK: [55:9 - 55:26] macro definition=CONCAT
// CHECK: [57:1 - 57:10] FunctionDecl=f:57:6 (Definition)
// CHECK: [58:4 - 58:8] VarDecl=my_var:58:8 (Definition)
-// CHECK: [58:8 - 58:14] macro instantiation=CONCAT:55:9
+// CHECK: [58:8 - 58:14] macro expansion=CONCAT:55:9
diff --git a/test/Index/code-completion.cpp b/test/Index/code-completion.cpp
index 62b9e4dd1adc..f75d61f1b04b 100644
--- a/test/Index/code-completion.cpp
+++ b/test/Index/code-completion.cpp
@@ -52,10 +52,21 @@ Z::operator int() const {
// CHECK-MEMBER: CXXDestructor:{ResultType void}{Informative X::}{TypedText ~X}{LeftParen (}{RightParen )}
// CHECK-MEMBER: CXXDestructor:{ResultType void}{Informative Y::}{TypedText ~Y}{LeftParen (}{RightParen )}
// CHECK-MEMBER: CXXDestructor:{ResultType void}{TypedText ~Z}{LeftParen (}{RightParen )}
+// CHECK-MEMBER: Completion contexts:
+// CHECK-MEMBER-NEXT: Dot member access
// CHECK-OVERLOAD: NotImplemented:{ResultType int &}{Text overloaded}{LeftParen (}{Text Z z}{Comma , }{CurrentParameter int second}{RightParen )}
// CHECK-OVERLOAD: NotImplemented:{ResultType float &}{Text overloaded}{LeftParen (}{Text int i}{Comma , }{CurrentParameter long second}{RightParen )}
// CHECK-OVERLOAD: NotImplemented:{ResultType double &}{Text overloaded}{LeftParen (}{Text float f}{Comma , }{CurrentParameter int second}{RightParen )}
+// CHECK-OVERLOAD: Completion contexts:
+// CHECK-OVERLOAD-NEXT: Any type
+// CHECK-OVERLOAD-NEXT: Any value
+// CHECK-OVERLOAD-NEXT: Enum tag
+// CHECK-OVERLOAD-NEXT: Union tag
+// CHECK-OVERLOAD-NEXT: Struct tag
+// CHECK-OVERLOAD-NEXT: Class name
+// CHECK-OVERLOAD-NEXT: Nested name specifier
+// CHECK-OVERLOAD-NEXT: Objective-C interface
// RUN: c-index-test -code-completion-at=%s:37:10 %s | FileCheck -check-prefix=CHECK-EXPR %s
// CHECK-EXPR: NotImplemented:{TypedText int} (50)
@@ -65,3 +76,12 @@ Z::operator int() const {
// CHECK-EXPR: FieldDecl:{ResultType float}{Text Y::}{TypedText member} (18)
// CHECK-EXPR: CXXMethod:{ResultType void}{TypedText memfunc}{LeftParen (}{Optional {Placeholder int i}}{RightParen )} (37)
// CHECK-EXPR: Namespace:{TypedText N}{Text ::} (75)
+// CHECK-EXPR: Completion contexts:
+// CHECK-EXPR-NEXT: Any type
+// CHECK-EXPR-NEXT: Any value
+// CHECK-EXPR-NEXT: Enum tag
+// CHECK-EXPR-NEXT: Union tag
+// CHECK-EXPR-NEXT: Struct tag
+// CHECK-EXPR-NEXT: Class name
+// CHECK-EXPR-NEXT: Nested name specifier
+// CHECK-EXPR-NEXT: Objective-C interface
diff --git a/test/Index/complete-exprs.m b/test/Index/complete-exprs.m
index 0446dcd2fbdf..dfa114dcc095 100644
--- a/test/Index/complete-exprs.m
+++ b/test/Index/complete-exprs.m
@@ -7,10 +7,10 @@ typedef signed char BOOL;
@property int prop1;
@end
-
+__strong id global;
@implementation A
- (int)method:(id)param1 {
-
+ void foo(id (^block)(id x, A* y));
for(BOOL B = YES; ; ) { }
}
@end
@@ -27,3 +27,8 @@ typedef signed char BOOL;
// CHECK-CC2: TypedefDecl:{TypedText BOOL} (50)
// CHECK-CC2: NotImplemented:{TypedText char} (50)
// CHECK-CC2: NotImplemented:{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} (40)
+// RUN: c-index-test -code-completion-at=%s:15:1 -fobjc-arc -fobjc-nonfragile-abi %s | FileCheck -check-prefix=CHECK-CC3 %s
+// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:15:1 -fobjc-arc -fobjc-nonfragile-abi %s | FileCheck -check-prefix=CHECK-CC3 %s
+// CHECK-CC3: FunctionDecl:{ResultType void}{TypedText foo}{LeftParen (}{Placeholder ^id(id x, A *y)block}{RightParen )} (34)
+// CHECK-CC3: VarDecl:{ResultType id}{TypedText global} (50)
+// CHECK-CC3: ParmDecl:{ResultType id}{TypedText param1} (34)
diff --git a/test/Index/complete-natural.m b/test/Index/complete-natural.m
index e1aba393ae71..326b8a7a0cdf 100644
--- a/test/Index/complete-natural.m
+++ b/test/Index/complete-natural.m
@@ -11,8 +11,9 @@ char in_char = 'a';
// RUN: c-index-test -code-completion-at=%s:4:32 %s > %t
// RUN: echo "DONE" >> %t
// RUN: FileCheck -check-prefix=CHECK-CC1 %s < %t
-// CHECK-CC1-NOT: :
-// CHECK-CC1: DONE
+// CHECK-CC1: Completion contexts:
+// CHECK-CC1-NEXT: Natural language
+// CHECK-CC1-NEXT: DONE
// RUN: c-index-test -code-completion-at=%s:5:18 %s > %t
// RUN: echo "DONE" >> %t
// RUN: FileCheck -check-prefix=CHECK-CC1 %s < %t
diff --git a/test/Index/complete-property-flags.m b/test/Index/complete-property-flags.m
index af9e214a292b..f2e08c36607c 100644
--- a/test/Index/complete-property-flags.m
+++ b/test/Index/complete-property-flags.m
@@ -16,6 +16,8 @@
// CHECK-CC1-NEXT: {TypedText readwrite}
// CHECK-CC1-NEXT: {TypedText retain}
// CHECK-CC1-NEXT: {TypedText setter}{Text = }{Placeholder method}
+// CHECK-CC1-NEXT: {TypedText strong}
+// CHECK-CC1-NEXT: {TypedText unsafe_unretained}
// RUN: c-index-test -code-completion-at=%s:8:18 %s | FileCheck -check-prefix=CHECK-CC2 %s
// CHECK-CC2: {TypedText getter}{Text = }{Placeholder method}
// CHECK-CC2-NEXT: {TypedText nonatomic}
diff --git a/test/Index/get-cursor.cpp b/test/Index/get-cursor.cpp
index f26d9825a102..2aa76c472569 100644
--- a/test/Index/get-cursor.cpp
+++ b/test/Index/get-cursor.cpp
@@ -31,6 +31,10 @@ struct YDerived : Y {
X getAnotherX() { return member; }
};
+void test() {
+ X foo;
+}
+
// RUN: c-index-test -cursor-at=%s:12:20 %s | FileCheck -check-prefix=CHECK-VALUE-REF %s
// RUN: c-index-test -cursor-at=%s:13:21 %s | FileCheck -check-prefix=CHECK-VALUE-REF %s
// RUN: c-index-test -cursor-at=%s:13:28 %s | FileCheck -check-prefix=CHECK-VALUE-REF %s
@@ -61,3 +65,6 @@ struct YDerived : Y {
// RUN: c-index-test -cursor-at=%s:27:10 %s | FileCheck -check-prefix=CHECK-IMPLICIT-MEMREF %s
// RUN: c-index-test -cursor-at=%s:31:28 %s | FileCheck -check-prefix=CHECK-IMPLICIT-MEMREF %s
// CHECK-IMPLICIT-MEMREF: MemberRefExpr=member:21:7
+
+// RUN: c-index-test -cursor-at=%s:35:5 %s | FileCheck -check-prefix=CHECK-DECL %s
+// CHECK-DECL: VarDecl=foo:35:5
diff --git a/test/Index/nested-macro-instantiations.cpp b/test/Index/nested-macro-instantiations.cpp
index d0c9bbb1e763..9d0c0521f404 100644
--- a/test/Index/nested-macro-instantiations.cpp
+++ b/test/Index/nested-macro-instantiations.cpp
@@ -7,14 +7,14 @@ WIBBLE(int x);
// RUN: env CINDEXTEST_NESTED_MACROS=1 c-index-test -test-load-source all %s | FileCheck -check-prefix CHECK-WITH-NESTED %s
// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_NESTED_MACROS=1 c-index-test -test-load-source all %s | FileCheck -check-prefix CHECK-WITH-NESTED %s
// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_NESTED_MACROS=1 c-index-test -test-load-source-reparse 5 all %s | FileCheck -check-prefix CHECK-WITH-NESTED %s
-// CHECK-WITH-NESTED: nested-macro-instantiations.cpp:5:1: macro instantiation=WIBBLE:3:9 Extent=[5:1 - 5:7]
-// CHECK-WITH-NESTED: nested-macro-instantiations.cpp:3:19: macro instantiation=BAR:2:9 Extent=[3:19 - 5:14]
-// CHECK-WITH-NESTED: nested-macro-instantiations.cpp:2:16: macro instantiation=FOO:1:9 Extent=[2:16 - 5:14]
+// CHECK-WITH-NESTED: nested-macro-instantiations.cpp:5:1: macro expansion=WIBBLE:3:9 Extent=[5:1 - 5:7]
+// CHECK-WITH-NESTED: nested-macro-instantiations.cpp:3:19: macro expansion=BAR:2:9 Extent=[3:19 - 5:14]
+// CHECK-WITH-NESTED: nested-macro-instantiations.cpp:2:16: macro expansion=FOO:1:9 Extent=[2:16 - 5:14]
// CHECK-WITH-NESTED: nested-macro-instantiations.cpp:5:1: VarDecl=x:5:1 (Definition) Extent=[5:1 - 5:14]
// RUN: c-index-test -test-load-source all %s | FileCheck -check-prefix CHECK-WITHOUT-NESTED %s
// RUN: env CINDEXTEST_EDITING=1 c-index-test -test-load-source all %s | FileCheck -check-prefix CHECK-WITHOUT-NESTED %s
// RUN: env CINDEXTEST_EDITING=1 c-index-test -test-load-source-reparse 5 all %s | FileCheck -check-prefix CHECK-WITHOUT-NESTED %s
-// CHECK-WITHOUT-NESTED: nested-macro-instantiations.cpp:5:1: macro instantiation=WIBBLE:3:9 Extent=[5:1 - 5:7]
-// CHECK-WITHOUT-NESTED-NOT: nested-macro-instantiations.cpp:3:19: macro instantiation=BAR:2:9 Extent=[3:19 - 5:14]
+// CHECK-WITHOUT-NESTED: nested-macro-instantiations.cpp:5:1: macro expansion=WIBBLE:3:9 Extent=[5:1 - 5:7]
+// CHECK-WITHOUT-NESTED-NOT: nested-macro-instantiations.cpp:3:19: macro expansion=BAR:2:9 Extent=[3:19 - 5:14]
// CHECK-WITHOUT-NESTED: nested-macro-instantiations.cpp:5:1: VarDecl=x:5:1 (Definition) Extent=[5:1 - 5:14]
diff --git a/test/Index/werror.c b/test/Index/werror.c
new file mode 100644
index 000000000000..150095d8599c
--- /dev/null
+++ b/test/Index/werror.c
@@ -0,0 +1,15 @@
+inline int *get_int_ptr(float *fp) {
+ return fp;
+}
+
+#ifdef FATAL
+void fatal(int);
+void fatal(float);
+#endif
+
+// CHECK-FATAL: translation errors
+
+// RUN: c-index-test -write-pch %t.pch -Werror %s
+// RUN: not c-index-test -write-pch %t.pch -DFATAL -Werror %s 2>%t.err
+// RUN: FileCheck -check-prefix=CHECK-FATAL %s < %t.err
+
diff --git a/test/Lexer/has_feature_objc_arc.m b/test/Lexer/has_feature_objc_arc.m
new file mode 100644
index 000000000000..cd41900c60b7
--- /dev/null
+++ b/test/Lexer/has_feature_objc_arc.m
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -E %s -fobjc-nonfragile-abi -fobjc-arc "-triple" "x86_64-apple-macosx10.7.0" -fobjc-runtime-has-weak | FileCheck --check-prefix=CHECK-ARC %s
+// RUN: %clang_cc1 -E %s -fobjc-nonfragile-abi -fobjc-arc "-triple" "x86_64-apple-macosx10.6.0" | FileCheck --check-prefix=CHECK-ARCLITE %s
+
+#if __has_feature(objc_arc)
+void has_objc_arc_feature();
+#else
+void no_objc_arc_feature();
+#endif
+
+#if __has_feature(objc_arc_weak)
+void has_objc_arc_weak_feature();
+#else
+void no_objc_arc_weak_feature();
+#endif
+
+// CHECK-ARC: void has_objc_arc_feature();
+// CHECK-ARC: void has_objc_arc_weak_feature();
+
+// CHECK-ARCLITE: void has_objc_arc_feature();
+// CHECK-ARCLITE: void no_objc_arc_weak_feature();
diff --git a/test/Makefile b/test/Makefile
index 050c3a51ddec..4fdafe1481b1 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -18,7 +18,7 @@ ifndef TESTARGS
ifdef VERBOSE
TESTARGS = -v
else
-TESTARGS = -s -v
+TESTARGS = -s -v
endif
endif
diff --git a/test/Misc/caret-diags-macros.c b/test/Misc/caret-diags-macros.c
index e45ad2a60518..ac83ecc69525 100644
--- a/test/Misc/caret-diags-macros.c
+++ b/test/Misc/caret-diags-macros.c
@@ -5,9 +5,9 @@
void foo() {
M1(
M2);
- // CHECK: {{.*}}:6:{{[0-9]+}}: warning: expression result unused
- // CHECK: {{.*}}:7:{{[0-9]+}}: note: instantiated from:
- // CHECK: {{.*}}:4:{{[0-9]+}}: note: instantiated from:
+ // CHECK: :7:{{[0-9]+}}: warning: expression result unused
+ // CHECK: :4:{{[0-9]+}}: note: expanded from:
+ // CHECK: :3:{{[0-9]+}}: note: expanded from:
}
#define A 1
@@ -15,13 +15,12 @@ void foo() {
#define C B
void bar() {
C;
- // CHECK: {{.*}}:17:{{[0-9]+}}: warning: expression result unused
- // CHECK: {{.*}}:15:{{[0-9]+}}: note: instantiated from:
- // CHECK: {{.*}}:14:{{[0-9]+}}: note: instantiated from:
- // CHECK: {{.*}}:13:{{[0-9]+}}: note: instantiated from:
+ // CHECK: :17:3: warning: expression result unused
+ // CHECK: :15:11: note: expanded from:
+ // CHECK: :14:11: note: expanded from:
+ // CHECK: :13:11: note: expanded from:
}
-
// rdar://7597492
#define sprintf(str, A, B) \
__builtin___sprintf_chk (str, 0, 42, A, B)
@@ -30,3 +29,95 @@ void baz(char *Msg) {
sprintf(Msg, " sizeof FoooLib : =%3u\n", 12LL);
}
+
+// PR9279: comprehensive tests for multi-level macro back traces
+#define macro_args1(x) x
+#define macro_args2(x) macro_args1(x)
+#define macro_args3(x) macro_args2(x)
+
+#define macro_many_args1(x, y, z) y
+#define macro_many_args2(x, y, z) macro_many_args1(x, y, z)
+#define macro_many_args3(x, y, z) macro_many_args2(x, y, z)
+
+void test() {
+ macro_args3(1);
+ // CHECK: {{.*}}:43:15: warning: expression result unused
+ // Also check that the 'caret' printing agrees with the location here where
+ // its easy to FileCheck.
+ // CHECK-NEXT: macro_args3(1);
+ // CHECK-NEXT: ~~~~~~~~~~~~^~
+ // CHECK: {{.*}}:36:36: note: expanded from:
+ // CHECK: {{.*}}:35:36: note: expanded from:
+ // CHECK: {{.*}}:34:24: note: expanded from:
+
+ macro_many_args3(
+ 1,
+ 2,
+ 3);
+ // CHECK: {{.*}}:55:5: warning: expression result unused
+ // CHECK: {{.*}}:40:55: note: expanded from:
+ // CHECK: {{.*}}:39:55: note: expanded from:
+ // CHECK: {{.*}}:38:35: note: expanded from:
+
+ macro_many_args3(
+ 1,
+ M2,
+ 3);
+ // CHECK: {{.*}}:64:5: warning: expression result unused
+ // CHECK: {{.*}}:4:12: note: expanded from:
+ // CHECK: {{.*}}:40:55: note: expanded from:
+ // CHECK: {{.*}}:39:55: note: expanded from:
+ // CHECK: {{.*}}:38:35: note: expanded from:
+
+ macro_many_args3(
+ 1,
+ macro_args2(2),
+ 3);
+ // CHECK: {{.*}}:74:17: warning: expression result unused
+ // This caret location needs to be printed *inside* a different macro's
+ // arguments.
+ // CHECK-NEXT: macro_args2(2),
+ // CHECK-NEXT: ~~~~~~~~~~~~^~~
+ // CHECK: {{.*}}:35:36: note: expanded from:
+ // CHECK: {{.*}}:34:24: note: expanded from:
+ // CHECK: {{.*}}:40:55: note: expanded from:
+ // CHECK: {{.*}}:39:55: note: expanded from:
+ // CHECK: {{.*}}:38:35: note: expanded from:
+}
+
+#define variadic_args1(x, y, ...) y
+#define variadic_args2(x, ...) variadic_args1(x, __VA_ARGS__)
+#define variadic_args3(x, y, ...) variadic_args2(x, y, __VA_ARGS__)
+
+void test2() {
+ variadic_args3(1, 2, 3, 4);
+ // CHECK: {{.*}}:93:21: warning: expression result unused
+ // CHECK-NEXT: variadic_args3(1, 2, 3, 4);
+ // CHECK-NEXT: ~~~~~~~~~~~~~~~~~~^~~~~~~~
+ // CHECK: {{.*}}:90:53: note: expanded from:
+ // CHECK: {{.*}}:89:50: note: expanded from:
+ // CHECK: {{.*}}:88:35: note: expanded from:
+}
+
+#define variadic_pasting_args1(x, y, z) y
+#define variadic_pasting_args2(x, ...) variadic_pasting_args1(x ## __VA_ARGS__)
+#define variadic_pasting_args2a(x, y, ...) variadic_pasting_args1(x, y ## __VA_ARGS__)
+#define variadic_pasting_args3(x, y, ...) variadic_pasting_args2(x, y, __VA_ARGS__)
+#define variadic_pasting_args3a(x, y, ...) variadic_pasting_args2a(x, y, __VA_ARGS__)
+
+void test3() {
+ variadic_pasting_args3(1, 2, 3, 4);
+ // CHECK: {{.*}}:109:32: warning: expression result unused
+ // CHECK: {{.*}}:105:72: note: expanded from:
+ // CHECK: {{.*}}:103:68: note: expanded from:
+ // CHECK: {{.*}}:102:41: note: expanded from:
+
+ variadic_pasting_args3a(1, 2, 3, 4);
+ // FIXME: It'd be really nice to retain the start location of the first token
+ // involved in the token paste instead of falling back on the full macro
+ // location in the first two locations here.
+ // CHECK: {{.*}}:115:3: warning: expression result unused
+ // CHECK: {{.*}}:106:44: note: expanded from:
+ // CHECK: {{.*}}:104:72: note: expanded from:
+ // CHECK: {{.*}}:102:41: note: expanded from:
+}
diff --git a/test/Misc/diag-aka-types.cpp b/test/Misc/diag-aka-types.cpp
index e0e6b8c7c7af..042c70b18a75 100644
--- a/test/Misc/diag-aka-types.cpp
+++ b/test/Misc/diag-aka-types.cpp
@@ -12,3 +12,41 @@ char c2 = ref; // expected-error{{'const foo_t' (aka 'const X')}}
// deduced auto should not produce an aka.
auto aut = X();
char c3 = aut; // expected-error{{from 'X' to 'char'}}
+
+// There are two classes named Foo::foo here. Make sure the message gives
+// a way to them apart.
+namespace Foo {
+ class foo {};
+}
+
+namespace bar {
+ namespace Foo {
+ class foo;
+ }
+ void f(Foo::foo* x); // expected-note{{passing argument to parameter 'x' here}}
+}
+
+void test(Foo::foo* x) {
+ bar::f(x); // expected-error{{cannot initialize a parameter of type 'Foo::foo *' (aka 'bar::Foo::foo *') with an lvalue of type 'Foo::foo *')}}
+}
+
+// PR9548 - "no known conversion from 'vector<string>' to 'vector<string>'"
+// vector<string> refers to two different types here. Make sure the message
+// gives a way to tell them apart.
+class versa_string;
+typedef versa_string string;
+
+namespace std {template <typename T> class vector;}
+using std::vector;
+
+void f(vector<string> v); // expected-note {{candidate function not viable: no known conversion from 'vector<string>' (aka 'std::vector<std::basic_string>') to 'vector<string>' (aka 'std::vector<versa_string>') for 1st argument}}
+
+namespace std {
+ class basic_string;
+ typedef basic_string string;
+ template <typename T> class vector {};
+ void g() {
+ vector<string> v;
+ f(v); // expected-error{{no matching function for call to 'f'}}
+ }
+}
diff --git a/test/Misc/include-stack-for-note-flag.cpp b/test/Misc/include-stack-for-note-flag.cpp
index 328999ded024..cfec5066a05f 100644
--- a/test/Misc/include-stack-for-note-flag.cpp
+++ b/test/Misc/include-stack-for-note-flag.cpp
@@ -18,11 +18,11 @@ bool macro(int x, int y) {
// STACK: note: candidate function not viable
// STACK: error: comparison between pointer and integer
// STACK: In file included from
-// STACK: note: instantiated from:
+// STACK: note: expanded from:
// STACKLESS: error: no matching function for call to 'foo'
// STACKLESS-NOT: In file included from
// STACKLESS: note: candidate function not viable
// STACKLESS: error: comparison between pointer and integer
// STACKLESS-NOT: In file included from
-// STACKLESS: note: instantiated from:
+// STACKLESS: note: expanded from:
diff --git a/test/Misc/macro-backtrace-limit.c b/test/Misc/macro-backtrace-limit.c
index 1e512febefa2..ee73c61afc64 100644
--- a/test/Misc/macro-backtrace-limit.c
+++ b/test/Misc/macro-backtrace-limit.c
@@ -17,16 +17,16 @@
void f(int *ip, float *fp) {
// CHECK: macro-backtrace-limit.c:31:7: warning: comparison of distinct pointer types ('int *' and 'float *')
// CHECK: if (M12(ip, fp)) { }
- // CHECK: macro-backtrace-limit.c:15:19: note: instantiated from:
+ // CHECK: macro-backtrace-limit.c:15:19: note: expanded from:
// CHECK: #define M12(A, B) M11(A, B)
- // CHECK: macro-backtrace-limit.c:14:19: note: instantiated from:
+ // CHECK: macro-backtrace-limit.c:14:19: note: expanded from:
// CHECK: #define M11(A, B) M10(A, B)
- // CHECK: note: (skipping 7 contexts in backtrace; use -fmacro-backtrace-limit=0 to see all)
- // CHECK: macro-backtrace-limit.c:6:18: note: instantiated from:
+ // CHECK: note: (skipping 7 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all)
+ // CHECK: macro-backtrace-limit.c:6:18: note: expanded from:
// CHECK: #define M3(A, B) M2(A, B)
- // CHECK: macro-backtrace-limit.c:5:18: note: instantiated from:
+ // CHECK: macro-backtrace-limit.c:5:18: note: expanded from:
// CHECK: #define M2(A, B) M1(A, B)
- // CHECK: macro-backtrace-limit.c:4:23: note: instantiated from:
+ // CHECK: macro-backtrace-limit.c:4:23: note: expanded from:
// CHECK: #define M1(A, B) ((A) < (B))
if (M12(ip, fp)) { }
}
diff --git a/test/PCH/Inputs/arc.h b/test/PCH/Inputs/arc.h
new file mode 100644
index 000000000000..793fc643f23c
--- /dev/null
+++ b/test/PCH/Inputs/arc.h
@@ -0,0 +1,20 @@
+// Header for Objective-C ARC-related PCH tests
+
+typedef const void *CFTypeRef;
+typedef const struct __CFString *CFStringRef;
+
+CFTypeRef CFCreateSomething();
+CFStringRef CFCreateString();
+CFTypeRef CFGetSomething();
+CFStringRef CFGetString();
+
+@interface NSString
+@end
+
+id CreateSomething();
+NSString *CreateNSString();
+
+typedef int array0[sizeof((__bridge id)CFCreateSomething())];
+typedef int array1[sizeof((__bridge CFTypeRef)CreateSomething())];
+
+
diff --git a/test/PCH/Inputs/typo.hpp b/test/PCH/Inputs/typo.hpp
new file mode 100644
index 000000000000..c81159500787
--- /dev/null
+++ b/test/PCH/Inputs/typo.hpp
@@ -0,0 +1,8 @@
+namespace boost {
+ template<typename F> class function {};
+
+ namespace graph {
+ template<typename V, typename E> class adjacency_list { };
+ };
+}
+
diff --git a/test/PCH/arc.m b/test/PCH/arc.m
new file mode 100644
index 000000000000..6f7b8704d9ea
--- /dev/null
+++ b/test/PCH/arc.m
@@ -0,0 +1,9 @@
+// Test this without pch.
+// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fobjc-arc -include %S/Inputs/arc.h -fsyntax-only -emit-llvm -o - %s
+
+// Test with pch.
+// RUN: %clang_cc1 -emit-pch -fblocks -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fobjc-arc -x objective-c-header -o %t %S/Inputs/arc.h
+// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fobjc-arc -include-pch %t -fsyntax-only -emit-llvm -o - %s
+
+array0 a0;
+array1 a1;
diff --git a/test/PCH/typo.cpp b/test/PCH/typo.cpp
new file mode 100644
index 000000000000..4c8861454d21
--- /dev/null
+++ b/test/PCH/typo.cpp
@@ -0,0 +1,17 @@
+
+// In header: expected-note{{ 'boost::function' declared here}}
+
+
+// In header: expected-note{{ 'boost::graph::adjacency_list' declared here}}
+
+
+
+adjacent_list<int, int> g; // expected-error{{no template named 'adjacent_list'; did you mean 'boost::graph::adjacency_list'?}}
+Function<int(int)> f; // expected-error{{no template named 'Function'; did you mean 'boost::function'?}}
+
+// Without PCH
+// RUN: %clang_cc1 -include %S/Inputs/typo.hpp -verify %s
+
+// With PCH
+// RUN: %clang_cc1 -x c++-header -emit-pch -o %t %S/Inputs/typo.hpp
+// RUN: %clang_cc1 -include-pch %t -verify %s
diff --git a/test/PCH/variables.c b/test/PCH/variables.c
index 58fd8ae84661..9f90b37d4162 100644
--- a/test/PCH/variables.c
+++ b/test/PCH/variables.c
@@ -1,18 +1,40 @@
// Test this without pch.
-// RUN: %clang_cc1 -include %S/variables.h -fsyntax-only -verify %s
+// RUN: %clang_cc1 -include %s -fsyntax-only -verify %s
// Test with pch.
-// RUN: %clang_cc1 -emit-pch -o %t %S/variables.h
+// RUN: %clang_cc1 -emit-pch -o %t %s
// RUN: %clang_cc1 -include-pch %t -fsyntax-only -verify %s
+#ifndef HEADER
+#define HEADER
+
+extern float y;
+extern int *ip, x;
+
+float z; // expected-note{{previous}}
+
+int z2 = 17; // expected-note{{previous}}
+
+#define MAKE_HAPPY(X) X##Happy
+int MAKE_HAPPY(Very); // expected-note{{previous definition is here}}
+
+#define A_MACRO_IN_THE_PCH 492
+#define FUNCLIKE_MACRO(X, Y) X ## Y
+
+#define PASTE2(x,y) x##y
+#define PASTE1(x,y) PASTE2(x,y)
+#define UNIQUE(x) PASTE1(x,__COUNTER__)
+
+int UNIQUE(a); // a0
+int UNIQUE(a); // a1
+
+#else
+
int *ip2 = &x;
float *fp = &ip; // expected-warning{{incompatible pointer types}}
-// FIXME:variables.h expected-note{{previous}}
double z; // expected-error{{redefinition}}
-// FIXME:variables.h expected-note{{previous}}
int z2 = 18; // expected-error{{redefinition}}
double VeryHappy; // expected-error{{redefinition}}
-// FIXME:variables.h expected-note{{previous definition is here}}
int Q = A_MACRO_IN_THE_PCH;
@@ -21,3 +43,5 @@ int R = FUNCLIKE_MACRO(A_MACRO_, IN_THE_PCH);
int UNIQUE(a); // a2
int *Arr[] = { &a0, &a1, &a2 };
+
+#endif
diff --git a/test/PCH/variables.h b/test/PCH/variables.h
index c9374297fc02..23d2cd30cceb 100644
--- a/test/PCH/variables.h
+++ b/test/PCH/variables.h
@@ -23,4 +23,3 @@ int MAKE_HAPPY(Very);
int UNIQUE(a); // a0
int UNIQUE(a); // a1
-
diff --git a/test/Parser/MicrosoftExtensions.c b/test/Parser/MicrosoftExtensions.c
index 2f5da5255b37..2b8451b26dda 100644
--- a/test/Parser/MicrosoftExtensions.c
+++ b/test/Parser/MicrosoftExtensions.c
@@ -60,5 +60,5 @@ void ms_intrinsics(int a)
{
__noop();
__assume(a);
-
+ __debugbreak();
}
diff --git a/test/Parser/parenthesis-balance.cpp b/test/Parser/parenthesis-balance.cpp
new file mode 100644
index 000000000000..5bfa6396039a
--- /dev/null
+++ b/test/Parser/parenthesis-balance.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+int f(int x) {
+ if (int foo = f(bar)) {} // expected-error{{use of undeclared identifier 'bar'}}
+ while (int foo = f(bar)) {} // expected-error{{use of undeclared identifier 'bar'}}
+ for (int foo = f(bar);;) {} // expected-error{{use of undeclared identifier 'bar'}}
+
+ int bar;
+ if (int foo = f(bar)) {}
+ while (int foo = f(bar)) {}
+ for (int foo = f(bar);;) {}
+
+ return 0;
+}
+
diff --git a/test/Parser/recovery.c b/test/Parser/recovery.c
index 1b33f0225bce..0747aecd6c04 100644
--- a/test/Parser/recovery.c
+++ b/test/Parser/recovery.c
@@ -74,6 +74,11 @@ void foo() {
X = 4 // expected-error{{expected ';' after expression}}
}
+// rdar://9045701
+void test9045701(int x) {
+#define VALUE 0
+ x = VALUE // expected-error{{expected ';' after expression}}
+}
// rdar://7980651
typedef int intptr_t; // expected-note {{'intptr_t' declared here}}
@@ -84,3 +89,12 @@ void test1(void) {
int y = x;
int z = y;
}
+
+void test2(int x) {
+#define VALUE2 VALUE+VALUE
+#define VALUE3 VALUE+0
+#define VALUE4(x) x+0
+ x = VALUE2 // expected-error{{expected ';' after expression}}
+ x = VALUE3 // expected-error{{expected ';' after expression}}
+ x = VALUE4(0) // expected-error{{expected ';' after expression}}
+}
diff --git a/test/Parser/switch-recovery.cpp b/test/Parser/switch-recovery.cpp
index 0e4dcfa3c637..a1df4261db45 100644
--- a/test/Parser/switch-recovery.cpp
+++ b/test/Parser/switch-recovery.cpp
@@ -156,3 +156,17 @@ void test12(int x) {
}
}
}
+
+void missing_statement_case(int x) {
+ switch (x) {
+ case 1:
+ case 0: // expected-error {{label at end of compound statement: expected statement}}
+ }
+}
+
+void missing_statement_default(int x) {
+ switch (x) {
+ case 0:
+ default: // expected-error {{label at end of compound statement: expected statement}}
+ }
+}
diff --git a/test/Preprocessor/include-directive2.c b/test/Preprocessor/include-directive2.c
index 5f1ee3cfbc26..b1a9940b4412 100644
--- a/test/Preprocessor/include-directive2.c
+++ b/test/Preprocessor/include-directive2.c
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -ffreestanding -Eonly -verify %s
-# define HEADER <float.h>
+# define HEADER <stdarg.h>
# include HEADER
diff --git a/test/Preprocessor/init.c b/test/Preprocessor/init.c
index b0515b3bba3c..f0920c9dedbd 100644
--- a/test/Preprocessor/init.c
+++ b/test/Preprocessor/init.c
@@ -15,7 +15,7 @@
// CXX0X:#define __GXX_EXPERIMENTAL_CXX0X__ 1
// CXX0X:#define __GXX_RTTI 1
// CXX0X:#define __GXX_WEAK__ 1
-// CXX0X:#define __cplusplus 199711L
+// CXX0X:#define __cplusplus 201103L
// CXX0X:#define __private_extern__ extern
//
//
diff --git a/test/Preprocessor/macro_paste_bad.c b/test/Preprocessor/macro_paste_bad.c
index 2af0173040dc..0a028a44686e 100644
--- a/test/Preprocessor/macro_paste_bad.c
+++ b/test/Preprocessor/macro_paste_bad.c
@@ -32,4 +32,3 @@ XX // expected-error {{attempt to use a poisoned identifier}}
#define VA __VA_ ## ARGS__
int VA; // expected-warning {{__VA_ARGS__ can only appear in the expansion of a C99 variadic macro}}
-
diff --git a/test/Preprocessor/macro_paste_hashhash.c b/test/Preprocessor/macro_paste_hashhash.c
index e7993cc0a351..f4b03bef2e16 100644
--- a/test/Preprocessor/macro_paste_hashhash.c
+++ b/test/Preprocessor/macro_paste_hashhash.c
@@ -1,7 +1,11 @@
-// RUN: %clang_cc1 -E %s | grep '^"x ## y";$'
+// RUN: %clang_cc1 -E %s | FileCheck %s
#define hash_hash # ## #
#define mkstr(a) # a
#define in_between(a) mkstr(a)
#define join(c, d) in_between(c hash_hash d)
+// CHECK: "x ## y";
join(x, y);
+#define FOO(x) A x B
+// CHECK: A ## B;
+FOO(##);
diff --git a/test/Preprocessor/macro_paste_simple.c b/test/Preprocessor/macro_paste_simple.c
index 563d7f44958d..0e62ba46dc96 100644
--- a/test/Preprocessor/macro_paste_simple.c
+++ b/test/Preprocessor/macro_paste_simple.c
@@ -1,5 +1,14 @@
-// RUN: %clang_cc1 %s -E | grep "barbaz123"
+// RUN: %clang_cc1 %s -E | FileCheck %s
#define FOO bar ## baz ## 123
-FOO
+// CHECK: A: barbaz123
+A: FOO
+
+// PR9981
+#define M1(A) A
+#define M2(X) X
+B: M1(M2(##))
+
+// CHECK: B: ##
+
diff --git a/test/Preprocessor/pragma_diagnostic_output.c b/test/Preprocessor/pragma_diagnostic_output.c
new file mode 100644
index 000000000000..e847107f8631
--- /dev/null
+++ b/test/Preprocessor/pragma_diagnostic_output.c
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -E %s | FileCheck %s
+// CHECK: #pragma GCC diagnostic warning "-Wall"
+#pragma GCC diagnostic warning "-Wall"
+// CHECK: #pragma GCC diagnostic ignored "-Wall"
+#pragma GCC diagnostic ignored "-Wall"
+// CHECK: #pragma GCC diagnostic error "-Wall"
+#pragma GCC diagnostic error "-Wall"
+// CHECK: #pragma GCC diagnostic fatal "-Wall"
+#pragma GCC diagnostic fatal "-Wall"
+// CHECK: #pragma GCC diagnostic push
+#pragma GCC diagnostic push
+// CHECK: #pragma GCC diagnostic pop
+#pragma GCC diagnostic pop
+
+// CHECK: #pragma clang diagnostic warning "-Wall"
+#pragma clang diagnostic warning "-Wall"
+// CHECK: #pragma clang diagnostic ignored "-Wall"
+#pragma clang diagnostic ignored "-Wall"
+// CHECK: #pragma clang diagnostic error "-Wall"
+#pragma clang diagnostic error "-Wall"
+// CHECK: #pragma clang diagnostic fatal "-Wall"
+#pragma clang diagnostic fatal "-Wall"
+// CHECK: #pragma clang diagnostic push
+#pragma clang diagnostic push
+// CHECK: #pragma clang diagnostic pop
+#pragma clang diagnostic pop
diff --git a/test/Preprocessor/warn-macro-unused.c b/test/Preprocessor/warn-macro-unused.c
index 8a6d7c25ca5f..c33aeb5df9d9 100644
--- a/test/Preprocessor/warn-macro-unused.c
+++ b/test/Preprocessor/warn-macro-unused.c
@@ -1,5 +1,10 @@
// RUN: %clang_cc1 %s -Wunused-macros -Dfoo -Dfoo -verify
+#include "warn-macro-unused.h"
+
#define unused // expected-warning {{macro is not used}}
#define unused
unused
+
+// rdar://9745065
+#undef unused_from_header // no warning
diff --git a/test/Preprocessor/warn-macro-unused.h b/test/Preprocessor/warn-macro-unused.h
new file mode 100644
index 000000000000..0c2c267fcfd6
--- /dev/null
+++ b/test/Preprocessor/warn-macro-unused.h
@@ -0,0 +1 @@
+#define unused_from_header
diff --git a/test/Sema/arm-neon-types.c b/test/Sema/arm-neon-types.c
index 1e8c9bf051e7..4be83da970bd 100644
--- a/test/Sema/arm-neon-types.c
+++ b/test/Sema/arm-neon-types.c
@@ -18,3 +18,10 @@ float32x2_t test3(uint32x2_t x) {
// removed when that is fixed.
return vcvt_n_f32_u32(x, 0); // expected-error {{argument should be a value from 1 to 32}} expected-error {{incompatible result type}}
}
+
+typedef signed int vSInt32 __attribute__((__vector_size__(16)));
+int32x4_t test4(int32x4_t a, vSInt32 b) {
+ a += b;
+ b += a;
+ return b += a;
+}
diff --git a/test/Sema/asm.c b/test/Sema/asm.c
index d8161c819b99..359431c4f93a 100644
--- a/test/Sema/asm.c
+++ b/test/Sema/asm.c
@@ -5,7 +5,7 @@ void f() {
asm ("foo\n" : : "a" (i + 2));
asm ("foo\n" : : "a" (f())); // expected-error {{invalid type 'void' in asm input}}
-
+
asm ("foo\n" : "=a" (f())); // expected-error {{invalid lvalue in asm output}}
asm ("foo\n" : "=a" (i + 2)); // expected-error {{invalid lvalue in asm output}}
@@ -21,7 +21,7 @@ void clobbers() {
asm ("nop" : : : "0", "%0", "#0");
asm ("nop" : : : "foo"); // expected-error {{unknown register name 'foo' in asm}}
asm ("nop" : : : "52");
- asm ("nop" : : : "53"); // expected-error {{unknown register name '53' in asm}}
+ asm ("nop" : : : "54"); // expected-error {{unknown register name '54' in asm}}
asm ("nop" : : : "-1"); // expected-error {{unknown register name '-1' in asm}}
asm ("nop" : : : "+1"); // expected-error {{unknown register name '+1' in asm}}
}
@@ -47,7 +47,7 @@ void test4(const volatile void *addr)
// <rdar://problem/6512595>
void test5() {
- asm("nop" : : "X" (8));
+ asm("nop" : : "X" (8));
}
// PR3385
@@ -56,7 +56,7 @@ void test6(long i) {
}
void asm_string_tests(int i) {
- asm("%!"); // simple asm string, %! is not an error.
+ asm("%!"); // simple asm string, %! is not an error.
asm("%!" : ); // expected-error {{invalid % escape in inline assembly string}}
asm("xyz %" : ); // expected-error {{invalid % escape in inline assembly string}}
@@ -64,7 +64,7 @@ void asm_string_tests(int i) {
asm ("%[somename]" :: "i"(4)); // expected-error {{unknown symbolic operand name in inline assembly string}}
asm ("%[somename" :: "i"(4)); // expected-error {{unterminated symbolic operand name in inline assembly string}}
asm ("%[]" :: "i"(4)); // expected-error {{empty symbolic operand name in inline assembly string}}
-
+
// PR3258
asm("%9" :: "i"(4)); // expected-error {{invalid operand number in inline asm string}}
asm("%1" : "+r"(i)); // ok, referring to input.
@@ -113,3 +113,13 @@ void test11(void) {
_Bool b;
asm volatile ("movb %%gs:%P2,%b0" : "=q"(b) : "0"(0), "i"(5L));
}
+
+void test12(void) {
+ register int cc __asm ("cc"); // expected-error{{unknown register name 'cc' in asm}}
+}
+
+// PR10223
+void test13(void) {
+ void *esp;
+ __asm__ volatile ("mov %%esp, %o" : "=r"(esp) : : ); // expected-error {{invalid % escape in inline assembly string}}
+}
diff --git a/test/Sema/attr-deprecated.c b/test/Sema/attr-deprecated.c
index b26171b86b0a..eeef0d757a70 100644
--- a/test/Sema/attr-deprecated.c
+++ b/test/Sema/attr-deprecated.c
@@ -37,6 +37,8 @@ struct foo {
void test1(struct foo *F) {
++F->x; // expected-warning {{'x' is deprecated}}
+ struct foo f1 = { .x = 17 }; // expected-warning {{'x' is deprecated}}
+ struct foo f2 = { 17 }; // expected-warning {{'x' is deprecated}}
}
typedef struct foo foo_dep __attribute__((deprecated));
diff --git a/test/Sema/attr-naked.c b/test/Sema/attr-naked.c
index 1ebd78438e2f..d9fa5423d9ef 100644
--- a/test/Sema/attr-naked.c
+++ b/test/Sema/attr-naked.c
@@ -2,6 +2,10 @@
int a __attribute__((naked)); // expected-warning {{'naked' attribute only applies to functions}}
+__attribute__((naked)) int t0(void) {
+ __asm__ volatile("mov r0, #0");
+}
+
void t1() __attribute__((naked));
void t2() __attribute__((naked(2))); // expected-error {{attribute takes no arguments}}
diff --git a/test/Sema/attr-unavailable-message.c b/test/Sema/attr-unavailable-message.c
index a1e047c8176b..9f663fc4efd4 100644
--- a/test/Sema/attr-unavailable-message.c
+++ b/test/Sema/attr-unavailable-message.c
@@ -16,3 +16,13 @@ void test_foo() {
}
char test2[__has_feature(attribute_unavailable_with_message) ? 1 : -1];
+
+// rdar://9623855
+void unavail(void) __attribute__((__unavailable__));
+void unavail(void) {
+ // No complains inside an unavailable function.
+ int ir = foo(1);
+ double dr = dfoo(1.0);
+ void (*fp)() = &bar;
+ double (*fp4)(double) = dfoo;
+}
diff --git a/test/Sema/attr-weak.c b/test/Sema/attr-weak.c
index 41c9fd7165ab..adedf1231f9e 100644
--- a/test/Sema/attr-weak.c
+++ b/test/Sema/attr-weak.c
@@ -12,3 +12,7 @@ struct __attribute__((weak)) s0 {}; // expected-warning {{'weak' attribute only
struct __attribute__((weak_import)) s1 {}; // expected-warning {{'weak_import' attribute only applies to variables and functions}}
static int x __attribute__((weak)); // expected-error {{weak declaration cannot have internal linkage}}
+
+// rdar://9538608
+int C; // expected-note {{previous definition is here}}
+extern int C __attribute__((weak_import)); // expected-warning {{an already-declared variable is made a weak_import declaration}}
diff --git a/test/Sema/bitfield.c b/test/Sema/bitfield.c
index 49c1c7d44361..a1ce894037f7 100644
--- a/test/Sema/bitfield.c
+++ b/test/Sema/bitfield.c
@@ -32,6 +32,7 @@ int y;
struct {unsigned x : 2;} x2;
__typeof__((x.x+=1)+1) y;
+__typeof__((0,x.x)+1) y;
__typeof__(x.x<<1) y;
int y;
diff --git a/test/Sema/compare.c b/test/Sema/compare.c
index 5221b172a602..cd973d4885c7 100644
--- a/test/Sema/compare.c
+++ b/test/Sema/compare.c
@@ -312,3 +312,18 @@ int rdar8511238() {
return 0;
return 20;
}
+
+// PR10336
+int test9(int sv, unsigned uv, long slv) {
+ return sv == (uv ^= slv); // expected-warning {{comparison of integers of different signs: 'int' and 'unsigned int'}}
+}
+
+void test10(void) {
+ int si;
+ unsigned int ui;
+ long sl;
+
+ _Bool b;
+ b = (si == (ui = sl)); // expected-warning {{comparison of integers of different signs: 'int' and 'unsigned int'}}
+ b = (si == (ui = sl&15));
+}
diff --git a/test/Sema/const-eval.c b/test/Sema/const-eval.c
index 56c429c58c2a..bdb40ae54be3 100644
--- a/test/Sema/const-eval.c
+++ b/test/Sema/const-eval.c
@@ -36,7 +36,7 @@ int g17[(3?:1) - 2];
EVAL_EXPR(18, ((int)((void*)10 + 10)) == 20 ? 1 : -1);
struct s {
- int a[(int)-1.0f]; // expected-error {{array size is negative}}
+ int a[(int)-1.0f]; // expected-error {{'a' declared as an array with a negative size}}
};
EVAL_EXPR(19, ((int)&*(char*)10 == 10 ? 1 : -1));
diff --git a/test/Sema/conversion-64-32.c b/test/Sema/conversion-64-32.c
index aa7282962f8e..112e995102c5 100644
--- a/test/Sema/conversion-64-32.c
+++ b/test/Sema/conversion-64-32.c
@@ -3,3 +3,13 @@
int test0(long v) {
return v; // expected-warning {{implicit conversion loses integer precision}}
}
+
+
+// rdar://9546171
+typedef int int4 __attribute__ ((vector_size(16)));
+typedef long long long2 __attribute__((__vector_size__(16)));
+
+int4 test1(long2 a) {
+ int4 v127 = a; // no warning.
+ return v127;
+}
diff --git a/test/Sema/conversion.c b/test/Sema/conversion.c
index 1eaf7082d67e..03204c63e965 100644
--- a/test/Sema/conversion.c
+++ b/test/Sema/conversion.c
@@ -335,3 +335,11 @@ void test_8559831(enum E8559831b value_a, E8559831c value_c) {
enum E8559831a a3 = value_d;
a3 = value_d;
}
+
+void test26(int si, long sl) {
+ si = sl % sl; // expected-warning {{implicit conversion loses integer precision: 'long' to 'int'}}
+ si = sl % si;
+ si = si % sl;
+ si = si / sl;
+ si = sl / si; // expected-warning {{implicit conversion loses integer precision: 'long' to 'int'}}
+}
diff --git a/test/Sema/ext_vector_casts.c b/test/Sema/ext_vector_casts.c
index 75d41ca077ef..848ec1f106f6 100644
--- a/test/Sema/ext_vector_casts.c
+++ b/test/Sema/ext_vector_casts.c
@@ -37,7 +37,7 @@ static void test() {
vec4 /= 5.2f;
vec4 %= 4; // expected-error {{invalid operands to binary expression ('float4' and 'int')}}
ivec4 %= 4;
- ivec4 += vec4; // expected-error {{can't convert between vector values of different size ('float4' and 'int4')}}
+ ivec4 += vec4; // expected-error {{can't convert between vector values of different size ('int4' and 'float4')}}
ivec4 += (int4)vec4;
ivec4 -= ivec4;
ivec4 |= ivec4;
diff --git a/test/Sema/extern-redecl.c b/test/Sema/extern-redecl.c
index 067e3c21e4c4..c176725df66b 100644
--- a/test/Sema/extern-redecl.c
+++ b/test/Sema/extern-redecl.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
// rdar: // 8125274
static int a16[]; // expected-warning {{tentative array definition assumed to have one element}}
@@ -7,3 +7,16 @@ void f16(void) {
extern int a16[];
}
+
+// PR10013: Scope of extern declarations extend past enclosing block
+extern int PR10013_x;
+int PR10013(void) {
+ int *PR10013_x = 0;
+ {
+ extern int PR10013_x;
+ extern int PR10013_x;
+ }
+
+ return PR10013_x; // expected-warning{{incompatible pointer to integer conversion}}
+}
+
diff --git a/test/Sema/format-strings.c b/test/Sema/format-strings.c
index c78095a04d7b..b47d3ca2616c 100644
--- a/test/Sema/format-strings.c
+++ b/test/Sema/format-strings.c
@@ -358,3 +358,17 @@ void pr9314() {
printf(__func__); // no-warning
}
+int printf(const char * restrict, ...) __attribute__((__format__ (__printf__, 1, 2)));
+
+void rdar9612060(void) {
+ printf("%s", 2); // expected-warning{{conversion specifies type 'char *' but the argument has type 'int'}}
+}
+
+void check_char(unsigned char x, signed char y) {
+ printf("%c", y); // no-warning
+ printf("%hhu", x); // no-warning
+ printf("%hhi", y); // no-warning
+ printf("%hhi", x); // no-warning
+ printf("%c", x); // no-warning
+ printf("%hhu", y); // no-warning
+}
diff --git a/test/Sema/i-c-e.c b/test/Sema/i-c-e.c
index 4d7007cd077c..1aac51e204f1 100644
--- a/test/Sema/i-c-e.c
+++ b/test/Sema/i-c-e.c
@@ -1,4 +1,4 @@
-// RUN: %clang %s -ffreestanding -fsyntax-only -Xclang -verify -pedantic -fpascal-strings
+// RUN: %clang %s -ffreestanding -fsyntax-only -Xclang -verify -pedantic -fpascal-strings -std=c99
#include <stdint.h>
#include <limits.h>
diff --git a/test/Sema/incomplete-decl.c b/test/Sema/incomplete-decl.c
index e5b6d5f0da6d..0214a0c6ce4c 100644
--- a/test/Sema/incomplete-decl.c
+++ b/test/Sema/incomplete-decl.c
@@ -22,7 +22,7 @@ void func() {
}
int h[]; // expected-warning {{tentative array definition assumed to have one element}}
-int (*i)[] = &h+1; // expected-error {{arithmetic on pointer to incomplete type 'int (*)[]'}}
+int (*i)[] = &h+1; // expected-error {{arithmetic on a pointer to an incomplete type 'int []'}}
struct bar j = {1}; // expected-error {{variable has incomplete type 'struct bar'}} \
expected-note {{forward declaration of 'struct bar'}}
diff --git a/test/Sema/inline-redef.c b/test/Sema/inline-redef.c
new file mode 100644
index 000000000000..4a46e1193e1f
--- /dev/null
+++ b/test/Sema/inline-redef.c
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -std=gnu89 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+#if __STDC_VERSION__ >= 199901
+#define GNU_INLINE __attribute((__gnu_inline__))
+#else
+#define GNU_INLINE
+#endif
+
+// PR5253
+// rdar://9559708 (same extension in C99 mode)
+// GNU Extension: check that we can redefine an extern inline function
+GNU_INLINE extern inline int f(int a) {return a;}
+int f(int b) {return b;} // expected-note{{previous definition is here}}
+// And now check that we can't redefine a normal function
+int f(int c) {return c;} // expected-error{{redefinition of 'f'}}
+
+// Check that we can redefine an extern inline function as a static function
+GNU_INLINE extern inline int g(int a) {return a;}
+static int g(int b) {return b;}
+
+// Check that we ensure the types of the two definitions are the same
+GNU_INLINE extern inline int h(int a) {return a;} // expected-note{{previous definition is here}}
+int h(short b) {return b;} // expected-error{{conflicting types for 'h'}}
diff --git a/test/Sema/inline.c b/test/Sema/inline.c
index b4795d3d936f..3c99f2433783 100644
--- a/test/Sema/inline.c
+++ b/test/Sema/inline.c
@@ -1,22 +1,6 @@
-// RUN: %clang_cc1 -std=gnu89 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
// Check that we don't allow illegal uses of inline
inline int a; // expected-error{{'inline' can only appear on functions}}
typedef inline int b; // expected-error{{'inline' can only appear on functions}}
int d(inline int a); // expected-error{{'inline' can only appear on functions}}
-
-// PR5253
-// GNU Extension: check that we can redefine an extern inline function
-extern inline int f(int a) {return a;}
-int f(int b) {return b;} // expected-note{{previous definition is here}}
-// And now check that we can't redefine a normal function
-int f(int c) {return c;} // expected-error{{redefinition of 'f'}}
-
-// Check that we can redefine an extern inline function as a static function
-extern inline int g(int a) {return a;}
-static int g(int b) {return b;}
-
-// Check that we ensure the types of the two definitions are the same
-extern inline int h(int a) {return a;} // expected-note{{previous definition is here}}
-int h(short b) {return b;} // expected-error{{conflicting types for 'h'}}
-
diff --git a/test/Sema/no-format-y2k-turnsoff-format.c b/test/Sema/no-format-y2k-turnsoff-format.c
new file mode 100644
index 000000000000..bd06e506ce09
--- /dev/null
+++ b/test/Sema/no-format-y2k-turnsoff-format.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -verify -fsyntax-only -Wformat -Wno-format-y2k
+// rdar://9504680
+
+void foo(const char *, ...) __attribute__((__format__ (__printf__, 1, 2)));
+
+void bar(unsigned int a) {
+ foo("%s", a); // expected-warning {{conversion specifies type 'char *' but the argument has type 'unsigned int'}}
+}
+
diff --git a/test/Sema/nonnull.c b/test/Sema/nonnull.c
new file mode 100644
index 000000000000..cea8e3d0ddc4
--- /dev/null
+++ b/test/Sema/nonnull.c
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -fsyntax-only %s
+// rdar://9584012
+
+typedef struct {
+ char *str;
+} Class;
+
+typedef union {
+ Class *object;
+} Instance __attribute__((transparent_union));
+
+__attribute__((nonnull(1))) void Class_init(Instance this, char *str) {
+ this.object->str = str;
+}
+
+int main(void) {
+ Class *obj;
+ Class_init(0, "Hello World"); // expected-warning {{null passed to a callee which requires a non-null argument}}
+ Class_init(obj, "Hello World");
+}
+
diff --git a/test/Sema/paren-list-expr-type.cpp b/test/Sema/paren-list-expr-type.cpp
new file mode 100644
index 000000000000..ad5b7fbf918e
--- /dev/null
+++ b/test/Sema/paren-list-expr-type.cpp
@@ -0,0 +1,17 @@
+// RUN: %clang -cc1 -ast-dump %s | not grep NULL
+// Makes sure that we don't introduce null types when handling
+// ParenListExpr.
+
+template<typename T> class X { void f() { X x(*this); } };
+
+template<typename T> class Y { Y() : t(1) {} T t; };
+
+template<typename T> class Z { Z() : b(true) {} const bool b; };
+
+template<typename T> class A : public Z<T> { A() : Z<T>() {} };
+
+class C {};
+template<typename T> class D : public C { D(): C() {} };
+
+void f() { (int)(1, 2); }
+
diff --git a/test/Sema/parentheses.c b/test/Sema/parentheses.c
index fa3c3c26b042..13ea3ecbe16a 100644
--- a/test/Sema/parentheses.c
+++ b/test/Sema/parentheses.c
@@ -26,6 +26,12 @@ void bitwise_rel(unsigned i) {
(void)(i == 1 | i == 2 | i == 3);
(void)(i != 1 & i != 2 & i != 3);
+ (void)(i & i | i); // expected-warning {{'&' within '|'}} \
+ // expected-note {{place parentheses around the '&' expression to silence this warning}}
+
+ (void)(i | i & i); // expected-warning {{'&' within '|'}} \
+ // expected-note {{place parentheses around the '&' expression to silence this warning}}
+
(void)(i ||
i && i); // expected-warning {{'&&' within '||'}} \
// expected-note {{place parentheses around the '&&' expression to silence this warning}}
@@ -42,21 +48,21 @@ void bitwise_rel(unsigned i) {
_Bool someConditionFunc();
void conditional_op(int x, int y, _Bool b) {
- (void)(x + someConditionFunc() ? 1 : 2); // expected-warning {{?: has lower precedence than +}} \
- // expected-note {{place parentheses around the ?: expression to evaluate it first}} \
- // expected-note {{place parentheses around the + expression to silence this warning}}
+ (void)(x + someConditionFunc() ? 1 : 2); // expected-warning {{operator '?:' has lower precedence than '+'}} \
+ // expected-note {{place parentheses around the '?:' expression to evaluate it first}} \
+ // expected-note {{place parentheses around the '+' expression to silence this warning}}
- (void)(x - b ? 1 : 2); // expected-warning {{?: has lower precedence than -}} \
- // expected-note {{place parentheses around the ?: expression to evaluate it first}} \
- // expected-note {{place parentheses around the - expression to silence this warning}}
+ (void)(x - b ? 1 : 2); // expected-warning {{operator '?:' has lower precedence than '-'}} \
+ // expected-note {{place parentheses around the '?:' expression to evaluate it first}} \
+ // expected-note {{place parentheses around the '-' expression to silence this warning}}
- (void)(x * (x == y) ? 1 : 2); // expected-warning {{?: has lower precedence than *}} \
- // expected-note {{place parentheses around the ?: expression to evaluate it first}} \
- // expected-note {{place parentheses around the * expression to silence this warning}}
+ (void)(x * (x == y) ? 1 : 2); // expected-warning {{operator '?:' has lower precedence than '*'}} \
+ // expected-note {{place parentheses around the '?:' expression to evaluate it first}} \
+ // expected-note {{place parentheses around the '*' expression to silence this warning}}
- (void)(x / !x ? 1 : 2); // expected-warning {{?: has lower precedence than /}} \
- // expected-note {{place parentheses around the ?: expression to evaluate it first}} \
- // expected-note {{place parentheses around the / expression to silence this warning}}
+ (void)(x / !x ? 1 : 2); // expected-warning {{operator '?:' has lower precedence than '/'}} \
+ // expected-note {{place parentheses around the '?:' expression to evaluate it first}} \
+ // expected-note {{place parentheses around the '/' expression to silence this warning}}
(void)(x % 2 ? 1 : 2); // no warning
diff --git a/test/Sema/parentheses.cpp b/test/Sema/parentheses.cpp
index a25f2a0ce7b8..252455dcad49 100644
--- a/test/Sema/parentheses.cpp
+++ b/test/Sema/parentheses.cpp
@@ -4,17 +4,17 @@
bool someConditionFunc();
void conditional_op(int x, int y, bool b) {
- (void)(x + someConditionFunc() ? 1 : 2); // expected-warning {{?: has lower precedence than +}} \
- // expected-note {{place parentheses around the ?: expression to evaluate it first}} \
- // expected-note {{place parentheses around the + expression to silence this warning}}
+ (void)(x + someConditionFunc() ? 1 : 2); // expected-warning {{operator '?:' has lower precedence than '+'}} \
+ // expected-note {{place parentheses around the '?:' expression to evaluate it first}} \
+ // expected-note {{place parentheses around the '+' expression to silence this warning}}
- (void)(x - b ? 1 : 2); // expected-warning {{?: has lower precedence than -}} \
- // expected-note {{place parentheses around the ?: expression to evaluate it first}} \
- // expected-note {{place parentheses around the - expression to silence this warning}}
+ (void)(x - b ? 1 : 2); // expected-warning {{operator '?:' has lower precedence than '-'}} \
+ // expected-note {{place parentheses around the '?:' expression to evaluate it first}} \
+ // expected-note {{place parentheses around the '-' expression to silence this warning}}
- (void)(x * (x == y) ? 1 : 2); // expected-warning {{?: has lower precedence than *}} \
- // expected-note {{place parentheses around the ?: expression to evaluate it first}} \
- // expected-note {{place parentheses around the * expression to silence this warning}}
+ (void)(x * (x == y) ? 1 : 2); // expected-warning {{operator '?:' has lower precedence than '*'}} \
+ // expected-note {{place parentheses around the '?:' expression to evaluate it first}} \
+ // expected-note {{place parentheses around the '*' expression to silence this warning}}
}
class Stream {
@@ -25,7 +25,21 @@ public:
};
void f(Stream& s, bool b) {
- (void)(s << b ? "foo" : "bar"); // expected-warning {{?: has lower precedence than <<}} \
- // expected-note {{place parentheses around the ?: expression to evaluate it first}} \
- // expected-note {{place parentheses around the << expression to silence this warning}}
+ (void)(s << b ? "foo" : "bar"); // expected-warning {{operator '?:' has lower precedence than '<<'}} \
+ // expected-note {{place parentheses around the '?:' expression to evaluate it first}} \
+ // expected-note {{place parentheses around the '<<' expression to silence this warning}}
+}
+
+struct S {
+ operator int() { return 42; }
+ friend S operator+(const S &lhs, bool) { return S(); }
+};
+
+void test(S *s, bool (S::*m_ptr)()) {
+ (void)(*s + true ? "foo" : "bar"); // expected-warning {{operator '?:' has lower precedence than '+'}} \
+ // expected-note {{place parentheses around the '?:' expression to evaluate it first}} \
+ // expected-note {{place parentheses around the '+' expression to silence this warning}}
+
+ // Don't crash on unusual member call expressions.
+ (void)((s->*m_ptr)() ? "foo" : "bar");
}
diff --git a/test/Sema/pointer-addition.c b/test/Sema/pointer-addition.c
index aa425a7fd9d9..21ce63b4381f 100644
--- a/test/Sema/pointer-addition.c
+++ b/test/Sema/pointer-addition.c
@@ -3,18 +3,19 @@
typedef struct S S; // expected-note 3 {{forward declaration of 'struct S'}}
void a(S* b, void* c) {
void (*fp)(int) = 0;
- b++; // expected-error {{arithmetic on pointer to incomplete type}}
- b += 1; // expected-error {{arithmetic on pointer to incomplete type}}
- c++; // expected-warning {{use of GNU void* extension}}
- c += 1; // expected-warning {{use of GNU void* extension}}
- c--; // expected-warning {{use of GNU void* extension}}
- c -= 1; // expected-warning {{use of GNU void* extension}}
- (void) c[1]; // expected-warning {{use of GNU void* extension}}
- b = 1+b; // expected-error {{arithmetic on pointer to incomplete type}}
+ b++; // expected-error {{arithmetic on a pointer to an incomplete type}}
+ b += 1; // expected-error {{arithmetic on a pointer to an incomplete type}}
+ c++; // expected-warning {{arithmetic on a pointer to void is a GNU extension}}
+ c += 1; // expected-warning {{arithmetic on a pointer to void is a GNU extension}}
+ c--; // expected-warning {{arithmetic on a pointer to void is a GNU extension}}
+ c -= 1; // expected-warning {{arithmetic on a pointer to void is a GNU extension}}
+ (void) c[1]; // expected-warning {{subscript of a pointer to void is a GNU extension}}
+ b = 1+b; // expected-error {{arithmetic on a pointer to an incomplete type}}
/* The next couple tests are only pedantic warnings in gcc */
void (*d)(S*,void*) = a;
- d += 1; // expected-warning {{arithmetic on pointer to function type 'void (*)(S *, void *)' is a GNU extension}}
- d++; // expected-warning {{arithmetic on pointer to function type 'void (*)(S *, void *)' is a GNU extension}}}
- d--; // expected-warning {{arithmetic on pointer to function type 'void (*)(S *, void *)' is a GNU extension}}
- d -= 1; // expected-warning {{arithmetic on pointer to function type 'void (*)(S *, void *)' is a GNU extension}}
+ d += 1; // expected-warning {{arithmetic on a pointer to the function type 'void (S *, void *)' is a GNU extension}}
+ d++; // expected-warning {{arithmetic on a pointer to the function type 'void (S *, void *)' is a GNU extension}}
+ d--; // expected-warning {{arithmetic on a pointer to the function type 'void (S *, void *)' is a GNU extension}}
+ d -= 1; // expected-warning {{arithmetic on a pointer to the function type 'void (S *, void *)' is a GNU extension}}
+ (void)(1 + d); // expected-warning {{arithmetic on a pointer to the function type 'void (S *, void *)' is a GNU extension}}
}
diff --git a/test/Sema/pointer-subtract-compat.c b/test/Sema/pointer-subtract-compat.c
index 70340c6a4cd3..b801f81473b3 100644
--- a/test/Sema/pointer-subtract-compat.c
+++ b/test/Sema/pointer-subtract-compat.c
@@ -7,5 +7,5 @@ int a(char* a, rchar* b) {
// <rdar://problem/6520707>
void f0(void (*fp)(void)) {
- int x = fp - fp; // expected-warning{{arithmetic on pointer to function type 'void (*)(void)' is a GNU extension}}
+ int x = fp - fp; // expected-warning{{arithmetic on pointers to the function type 'void (void)' is a GNU extension}}
}
diff --git a/test/Sema/shift.c b/test/Sema/shift.c
index 28407be079f4..142d83c43d92 100644
--- a/test/Sema/shift.c
+++ b/test/Sema/shift.c
@@ -38,7 +38,7 @@ void test() {
int i;
i = 1 << (WORD_BIT - 2);
i = 2 << (WORD_BIT - 1); // expected-warning {{bits to represent, but 'int' only has}}
- i = 1 << (WORD_BIT - 1); // expected-warning {{overrides the sign bit of the shift expression}}
+ i = 1 << (WORD_BIT - 1); // expected-warning {{sets the sign bit of the shift expression}}
i = -1 << (WORD_BIT - 1);
i = 0 << (WORD_BIT - 1);
i = (char)1 << (WORD_BIT - 2);
diff --git a/test/Sema/sign-conversion.c b/test/Sema/sign-conversion.c
new file mode 100644
index 000000000000..4b1ee7542158
--- /dev/null
+++ b/test/Sema/sign-conversion.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wsign-conversion %s
+
+// PR9345: make a subgroup of -Wconversion for signedness changes
+
+void test(int x) {
+ unsigned t0 = x; // expected-warning {{implicit conversion changes signedness}}
+ unsigned t1 = (t0 == 5 ? x : 0); // expected-warning {{operand of ? changes signedness}}
+}
diff --git a/test/Sema/struct-decl.c b/test/Sema/struct-decl.c
index e1c7073e01b2..6070e875f5a4 100644
--- a/test/Sema/struct-decl.c
+++ b/test/Sema/struct-decl.c
@@ -6,7 +6,7 @@ struct bar {
struct foo {
char name[(int)&((struct bar *)0)->n];
- char name2[(int)&((struct bar *)0)->n - 1]; //expected-error{{array size is negative}}
+ char name2[(int)&((struct bar *)0)->n - 1]; //expected-error{{'name2' declared as an array with a negative size}}
};
// PR3430
diff --git a/test/Sema/typecheck-binop.c b/test/Sema/typecheck-binop.c
index 712dad279db5..be52d0bd8444 100644
--- a/test/Sema/typecheck-binop.c
+++ b/test/Sema/typecheck-binop.c
@@ -7,15 +7,15 @@ int sub1(int *a, double *b) {
}
void *sub2(struct incomplete *P) {
- return P-4; /* expected-error{{subtraction of pointer 'struct incomplete *' requires pointee to be a complete object type}} */
+ return P-4; /* expected-error{{arithmetic on a pointer to an incomplete type 'struct incomplete'}} */
}
void *sub3(void *P) {
- return P-4; /* expected-warning{{GNU void* extension}} */
+ return P-4; /* expected-warning{{arithmetic on a pointer to void is a GNU extension}} */
}
int sub4(void *P, void *Q) {
- return P-Q; /* expected-warning{{GNU void* extension}} */
+ return P-Q; /* expected-warning{{arithmetic on pointers to void is a GNU extension}} */
}
int sub5(void *P, int *Q) {
diff --git a/test/Sema/typedef-variable-type.c b/test/Sema/typedef-variable-type.c
index b805b1e0578f..8a7ee8b911c0 100644
--- a/test/Sema/typedef-variable-type.c
+++ b/test/Sema/typedef-variable-type.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -verify -fsyntax-only -pedantic -Wno-typedef-redefinition
+// RUN: %clang_cc1 %s -verify -fsyntax-only -pedantic -Wno-typedef-redefinition -std=c99
// Make sure we accept a single typedef
typedef int (*a)[!.0]; // expected-warning{{size of static array must be an integer constant expression}}
diff --git a/test/Sema/uninit-variables.c b/test/Sema/uninit-variables.c
index b70a29519c41..0caab3df18c0 100644
--- a/test/Sema/uninit-variables.c
+++ b/test/Sema/uninit-variables.c
@@ -352,3 +352,18 @@ int test52(int a, int b) {
}
return x; // expected-warning {{variable 'x' may be uninitialized when used here}}
}
+
+// This CFG caused the uninitialized values warning to inf-loop.
+extern int PR10379_g();
+void PR10379_f(int *len) {
+ int new_len; // expected-note {{variable 'new_len' is declared here}} expected-note{{add initialization to silence this warning}}
+ for (int i = 0; i < 42 && PR10379_g() == 0; i++) {
+ if (PR10379_g() == 1)
+ continue;
+ if (PR10379_g() == 2)
+ PR10379_f(&new_len);
+ else if (PR10379_g() == 3)
+ PR10379_f(&new_len);
+ *len += new_len; // expected-warning {{variable 'new_len' may be uninitialized when used here}}
+ }
+}
diff --git a/test/Sema/varargs.c b/test/Sema/varargs.c
index e399f89ae0aa..07081edd1d95 100644
--- a/test/Sema/varargs.c
+++ b/test/Sema/varargs.c
@@ -61,3 +61,18 @@ void f7(int a, ...) {
__builtin_va_end(ap);
}
+void f8(int a, ...) {
+ __builtin_va_list ap;
+ __builtin_va_start(ap, a);
+ (void)__builtin_va_arg(ap, void); // expected-error {{second argument to 'va_arg' is of incomplete type 'void'}}
+ __builtin_va_end(ap);
+}
+
+enum E { x = -1, y = 2, z = 10000 };
+void f9(__builtin_va_list args)
+{
+ (void)__builtin_va_arg(args, float); // expected-warning {{second argument to 'va_arg' is of promotable type 'float'}}
+ (void)__builtin_va_arg(args, enum E); // Don't warn here in C
+ (void)__builtin_va_arg(args, short); // expected-warning {{second argument to 'va_arg' is of promotable type 'short'}}
+ (void)__builtin_va_arg(args, char); // expected-warning {{second argument to 'va_arg' is of promotable type 'char'}}
+}
diff --git a/test/Sema/vla.c b/test/Sema/vla.c
index ebf9b889ee2a..fd7a6bf3d72f 100644
--- a/test/Sema/vla.c
+++ b/test/Sema/vla.c
@@ -42,7 +42,7 @@ void f3()
}
// PR3663
-static const unsigned array[((2 * (int)((((4) / 2) + 1.0/3.0) * (4) - 1e-8)) + 1)]; // expected-warning {{size of static array must be an integer constant expression}}
+static const unsigned array[((2 * (int)((((4) / 2) + 1.0/3.0) * (4) - 1e-8)) + 1)]; // expected-warning {{variable length array folded to constant array as an extension}}
int a[*]; // expected-error {{star modifier used outside of function prototype}}
int f4(int a[*][*]);
@@ -53,7 +53,7 @@ int pr2044b;
int (*pr2044c(void))[pr2044b]; // expected-error {{variably modified type}}
const int f5_ci = 1;
-void f5() { char a[][f5_ci] = {""}; } // expected-error {{variable-sized object may not be initialized}}
+void f5() { char a[][f5_ci] = {""}; } // expected-warning {{variable length array folded to constant array as an extension}}
// PR5185
void pr5185(int a[*]);
diff --git a/test/Sema/warn-sizeof-arrayarg.c b/test/Sema/warn-sizeof-arrayarg.c
new file mode 100644
index 000000000000..ba8a5fa975a4
--- /dev/null
+++ b/test/Sema/warn-sizeof-arrayarg.c
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+typedef int Arr[10];
+
+typedef int trungl_int;
+
+void f(int a[10], Arr arr) { // \
+// expected-note {{declared here}} \
+// expected-note {{declared here}} \
+// expected-note {{declared here}} \
+// expected-note {{declared here}}
+
+ /* Should warn. */
+ (void)sizeof(a); // \
+ // expected-warning{{sizeof on array function parameter will return size of 'int *' instead of 'int [10]'}}
+ (void)sizeof((((a)))); // \
+ // expected-warning{{sizeof on array function parameter will return size of 'int *' instead of 'int [10]'}}
+ (void)sizeof a; // \
+ // expected-warning{{sizeof on array function parameter will return size of 'int *' instead of 'int [10]'}}
+ (void)sizeof arr; // \
+ // expected-warning{{sizeof on array function parameter will return size of 'int *' instead of 'Arr' (aka 'int [10]')}}
+
+ /* Shouldn't warn. */
+ int b[10];
+ (void)sizeof b;
+ Arr brr;
+ (void)sizeof brr;
+ (void)sizeof(Arr);
+ (void)sizeof(int);
+}
diff --git a/test/Sema/x86-builtin-palignr.c b/test/Sema/x86-builtin-palignr.c
index 83719a379fa6..6e1303c8a105 100644
--- a/test/Sema/x86-builtin-palignr.c
+++ b/test/Sema/x86-builtin-palignr.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -ffreestanding -fsyntax-only -target-feature +ssse3 -verify -triple x86_64-pc-linux-gnu %s
-// RUN: %clang_cc1 -ffreestanding -fsyntax-only -target-feature +ssse3 -verify -triple i686-apple-darwin10 %s
+// RUN: %clang_cc1 -ffreestanding -fsyntax-only -target-feature +ssse3 -target-feature +mmx -verify -triple x86_64-pc-linux-gnu %s
+// RUN: %clang_cc1 -ffreestanding -fsyntax-only -target-feature +ssse3 -target-feature +mmx -verify -triple i686-apple-darwin10 %s
#include <tmmintrin.h>
diff --git a/test/SemaCXX/PR10243.cpp b/test/SemaCXX/PR10243.cpp
new file mode 100644
index 000000000000..9a5851049803
--- /dev/null
+++ b/test/SemaCXX/PR10243.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+
+struct S; // expected-note 4{{forward declaration of 'S'}}
+
+struct T0 {
+ S s; // expected-error{{field has incomplete type 'S'}}
+ T0() = default;
+};
+
+struct T1 {
+ S s; // expected-error{{field has incomplete type 'S'}}
+ T1(T1&) = default;
+};
+
+struct T2 {
+ S s; // expected-error{{field has incomplete type 'S'}}
+ T2& operator=(T2&) = default;
+};
+
+struct T3 {
+ S s; // expected-error{{field has incomplete type 'S'}}
+ ~T3() = default;
+};
diff --git a/test/SemaCXX/PR7410.cpp b/test/SemaCXX/PR7410.cpp
new file mode 100644
index 000000000000..6d2cda90b1d3
--- /dev/null
+++ b/test/SemaCXX/PR7410.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+struct BaseReturn {};
+
+struct Base {
+ virtual BaseReturn Foo() = 0; // expected-note{{overridden virtual function is here}}
+};
+struct X {};
+struct Derived : Base {
+ X Foo(); // expected-error{{virtual function 'Foo' has a different return type ('X') than the function it overrides (which has return type 'BaseReturn')}}
+};
+
+Derived d;
diff --git a/test/SemaCXX/PR9459.cpp b/test/SemaCXX/PR9459.cpp
index dfb242dc5952..2b96f34e8a72 100644
--- a/test/SemaCXX/PR9459.cpp
+++ b/test/SemaCXX/PR9459.cpp
@@ -3,5 +3,5 @@
// Don't crash.
template<typename>struct ae_same;
-template<typename>struct ts{}ap()
+template<typename>struct ts{}ap() // expected-error {{expected ';' after struct}} expected-error {{requires a type specifier}}
{ts<a>::ap<ae_same<int>::&ae_same<>>::p(a); }; // expected-error {{use of undeclared identifier 'a'}}
diff --git a/test/SemaCXX/alignof-sizeof-reference.cpp b/test/SemaCXX/alignof-sizeof-reference.cpp
index b517e43cf1ff..93ba203ae112 100644
--- a/test/SemaCXX/alignof-sizeof-reference.cpp
+++ b/test/SemaCXX/alignof-sizeof-reference.cpp
@@ -13,3 +13,9 @@ void f(int); // expected-note{{candidate function}}
void g() {
sizeof(&f); // expected-error{{cannot resolve overloaded function 'f' from context}}
}
+
+template<typename T> void f_template(); // expected-note{{candidate function}}
+template<typename T> void f_template(T*); // expected-note{{candidate function}}
+void rdar9659191() {
+ (void)alignof(f_template<int>); // expected-error{{cannot resolve overloaded function 'f_template' from context}}
+}
diff --git a/test/SemaCXX/attr-unavailable.cpp b/test/SemaCXX/attr-unavailable.cpp
index 5f34ed990413..2d82668a205a 100644
--- a/test/SemaCXX/attr-unavailable.cpp
+++ b/test/SemaCXX/attr-unavailable.cpp
@@ -28,3 +28,12 @@ void bar() {
foo(); // expected-error {{call to unavailable function 'foo': not available - replaced}}
}
}
+
+void unavail(short* sp) __attribute__((__unavailable__));
+void unavail(short* sp) {
+ // No complains inside an unavailable function.
+ int &ir = foo(1);
+ double &dr = foo(1.0);
+ foo(sp);
+ foo();
+}
diff --git a/test/SemaCXX/c99-variable-length-array.cpp b/test/SemaCXX/c99-variable-length-array.cpp
index 98df1dbfe81e..3f1d6a8a55c0 100644
--- a/test/SemaCXX/c99-variable-length-array.cpp
+++ b/test/SemaCXX/c99-variable-length-array.cpp
@@ -121,3 +121,12 @@ namespace PR8209 {
(void)new vla_type; // expected-error{{variably}}
}
}
+
+namespace rdar8733881 { // rdar://8733881
+
+static const int k_cVal3 = (int)(1000*0.2f);
+ int f() {
+ // Ok, fold to a constant size array as an extension.
+ char rgch[k_cVal3] = {0};
+ }
+}
diff --git a/test/SemaCXX/condition.cpp b/test/SemaCXX/condition.cpp
index 61d1762be85f..3441bae67076 100644
--- a/test/SemaCXX/condition.cpp
+++ b/test/SemaCXX/condition.cpp
@@ -16,8 +16,9 @@ void test() {
for (;s;) ; // expected-error {{value of type 'struct S' is not contextually convertible to 'bool'}}
switch (s) {} // expected-error {{statement requires expression of integer type ('struct S' invalid)}}
- while (struct S {} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{no viable conversion}} expected-error {{value of type 'struct S' is not contextually convertible to 'bool'}} expected-note{{candidate constructor (the implicit copy constructor)}}
- while (struct {} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{no viable conversion}} expected-error {{not contextually convertible to 'bool'}} expected-note{{candidate constructor (the implicit copy constructor)}}
+ while (struct NewS *x=0) ;
+ while (struct S {} *x=0) ; // expected-error {{types may not be defined in conditions}}
+ while (struct {} *x=0) ; // expected-error {{types may not be defined in conditions}}
switch (enum {E} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{cannot initialize}} \
// expected-warning{{enumeration value 'E' not handled in switch}}
diff --git a/test/SemaCXX/conversion-function.cpp b/test/SemaCXX/conversion-function.cpp
index aa47ae0f4825..a7a178244c80 100644
--- a/test/SemaCXX/conversion-function.cpp
+++ b/test/SemaCXX/conversion-function.cpp
@@ -378,3 +378,17 @@ namespace PR9336 {
generic_list<generic_list<int> > l;
array<array<int> > a = l;
}
+
+namespace PR8800 {
+ struct A;
+ struct C {
+ operator A&();
+ };
+ void f() {
+ C c;
+ A& a1(c);
+ A& a2 = c;
+ A& a3 = static_cast<A&>(c);
+ A& a4 = (A&)c;
+ }
+}
diff --git a/test/SemaCXX/copy-assignment.cpp b/test/SemaCXX/copy-assignment.cpp
index f3dadc445040..7aca9d6a80ab 100644
--- a/test/SemaCXX/copy-assignment.cpp
+++ b/test/SemaCXX/copy-assignment.cpp
@@ -99,15 +99,17 @@ void test() {
// <rdar://problem/8315440>: Don't crash
// FIXME: the recovery here is really bad.
-namespace test1 { // expected-note{{to match this '{'}}
- template<typename T> class A : public unknown::X { // expected-error {{undeclared identifier 'unknown'}} expected-error {{expected class name}} \
- // expected-note{{template parameter is declared here}}
+namespace test1 {
+ template<typename T> class A : public unknown::X { // expected-error {{undeclared identifier 'unknown'}} expected-error {{expected class name}}
A(UndeclaredType n) : X(n) {} // expected-error{{expected ')'}} expected-note{{to match this '('}} \
- // expected-error{{use of undeclared identifier 'n'}}
+ // expected-error{{use of undeclared identifier 'n'}} \
+ // expected-error{{expected ';' at end of declaration list}} \
+ // expected-error{{field has incomplete type 'test1::A<char>'}}
};
- template<typename T> class B : public A<T> { // expected-error{{declaration of 'T' shadows template parameter}}
+ template<typename T> class B : public A<T> {
virtual void foo() {}
};
- extern template class A<char>; // expected-error{{expected member name or ';' after declaration specifiers}}
- extern template class B<char>; // expected-error{{expected member name or ';' after declaration specifiers}}
-} // expected-error{{expected ';' after class}} // expected-error{{expected '}'}}
+ extern template class A<char>; // expected-note {{in instantiation of template class 'test1::A<char>' requested here}} \
+ // expected-note {{definition of 'test1::A<char>' is not complete until the closing '}'}}
+ extern template class B<char>;
+}
diff --git a/test/SemaCXX/crashes.cpp b/test/SemaCXX/crashes.cpp
index c75b0401fed6..b77248ef4104 100644
--- a/test/SemaCXX/crashes.cpp
+++ b/test/SemaCXX/crashes.cpp
@@ -95,3 +95,12 @@ namespace PR9026 {
Write(x);
}
}
+
+namespace PR10270 {
+ template<typename T> class C;
+ template<typename T> void f() {
+ if (C<T> == 1) // expected-error{{expected unqualified-id}} \
+ // expected-error{{invalid '==' at end of declaration}}
+ return;
+ }
+}
diff --git a/test/SemaCXX/decltype.cpp b/test/SemaCXX/decltype.cpp
index d4ef7e33a1d1..f61a92b71e1e 100644
--- a/test/SemaCXX/decltype.cpp
+++ b/test/SemaCXX/decltype.cpp
@@ -16,3 +16,8 @@ void test_f2() {
float &fr = f2(AC().a);
}
+namespace pr10154 {
+ class A{
+ A(decltype(nullptr) param);
+ };
+} \ No newline at end of file
diff --git a/test/SemaCXX/enum-scoped.cpp b/test/SemaCXX/enum-scoped.cpp
index fc871cf37920..73e7578ecb6e 100644
--- a/test/SemaCXX/enum-scoped.cpp
+++ b/test/SemaCXX/enum-scoped.cpp
@@ -119,3 +119,26 @@ namespace rdar9366066 {
x % 8; // expected-error{{invalid operands to binary expression ('rdar9366066::X' and 'int')}}
}
}
+
+// Part 1 of PR10264
+namespace test5 {
+ namespace ns {
+ typedef unsigned Atype;
+ enum A : Atype;
+ }
+ enum ns::A : ns::Atype {
+ x, y, z
+ };
+}
+
+// Part 2 of PR10264
+namespace test6 {
+ enum A : unsigned;
+ struct A::a; // expected-error {{incomplete type 'test6::A' named in nested name specifier}}
+ enum A::b; // expected-error {{incomplete type 'test6::A' named in nested name specifier}}
+ int A::c; // expected-error {{incomplete type 'test6::A' named in nested name specifier}}
+ void A::d(); // expected-error {{incomplete type 'test6::A' named in nested name specifier}}
+ void test() {
+ (void) A::e; // expected-error {{incomplete type 'test6::A' named in nested name specifier}}
+ }
+}
diff --git a/test/SemaCXX/expressions.cpp b/test/SemaCXX/expressions.cpp
index 95ece48e51fe..8a294face380 100644
--- a/test/SemaCXX/expressions.cpp
+++ b/test/SemaCXX/expressions.cpp
@@ -63,3 +63,25 @@ int test2(int x) {
return x && (-1); // expected-warning {{use of logical && with constant operand; switch to bitwise & or remove constant}}
return x && (5); // expected-warning {{use of logical && with constant operand; switch to bitwise & or remove constant}}
}
+
+template<unsigned int A, unsigned int B> struct S
+{
+ enum {
+ e1 = A && B,
+ e2 = A && 7 // expected-warning {{use of logical && with constant operand; switch to bitwise & or remove constant}}
+ };
+
+ int foo() {
+ int x = A && B;
+ int y = B && 3; // expected-warning {{use of logical && with constant operand; switch to bitwise & or remove constant}}
+
+ return x + y;
+ }
+};
+
+void test3() {
+ S<5, 8> s1;
+ S<2, 7> s2;
+ (void)s1.foo();
+ (void)s2.foo();
+}
diff --git a/test/SemaCXX/for-range-unused.cpp b/test/SemaCXX/for-range-unused.cpp
new file mode 100644
index 000000000000..7b7d84d3f9c8
--- /dev/null
+++ b/test/SemaCXX/for-range-unused.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x -Wunused
+
+// PR9968: We used to warn that __range is unused in a dependent for-range.
+
+template <typename T>
+ struct Vector {
+ void doIt() {
+ int a; // expected-warning {{unused variable 'a'}}
+
+ for (auto& e : elements)
+ ;
+ }
+
+ T elements[10];
+ };
+
+
+int main(int, char**) {
+ Vector<int> vector;
+ vector.doIt();
+}
diff --git a/test/SemaCXX/function-overload-typo-crash.cpp b/test/SemaCXX/function-overload-typo-crash.cpp
new file mode 100644
index 000000000000..0fea312a97f2
--- /dev/null
+++ b/test/SemaCXX/function-overload-typo-crash.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// PR10283
+void min();
+void min(int);
+
+template <typename T> void max(T);
+
+void f() {
+ fin(); //expected-error {{use of undeclared identifier 'fin'; did you mean 'min'}}
+ fax(0); //expected-error {{use of undeclared identifier 'fax'; did you mean 'max'}}
+}
diff --git a/test/SemaCXX/generalized-initializers.cpp b/test/SemaCXX/generalized-initializers.cpp
index ec37a0c9ac18..6e2bee7e301d 100644
--- a/test/SemaCXX/generalized-initializers.cpp
+++ b/test/SemaCXX/generalized-initializers.cpp
@@ -85,23 +85,52 @@ namespace integral {
namespace objects {
+ struct X1 { X1(int); };
+ struct X2 { explicit X2(int); };
+
template <int N>
struct A {
A() { static_assert(N == 0, ""); }
A(int, double) { static_assert(N == 1, ""); }
- A(int, int) { static_assert(N == 2, ""); }
A(std::initializer_list<int>) { static_assert(N == 3, ""); }
};
- void initialization() {
+ template <int N>
+ struct D {
+ D(std::initializer_list<int>) { static_assert(N == 0, ""); } // expected-note 1 {{candidate}}
+ D(std::initializer_list<double>) { static_assert(N == 1, ""); } // expected-note 1 {{candidate}}
+ };
+
+ template <int N>
+ struct E {
+ E(int, int) { static_assert(N == 0, ""); }
+ E(X1, int) { static_assert(N == 1, ""); }
+ };
+
+ void overload_resolution() {
{ A<0> a{}; }
{ A<0> a = {}; }
- { A<1> a{1, 1.0}; }
- { A<1> a = {1, 1.0}; }
+ // Narrowing conversions don't affect viability. The next two choose
+ // the initializer_list constructor.
+ { A<3> a{1, 1.0}; } // expected-error {{narrowing conversion}}
+ { A<3> a = {1, 1.0}; } // expected-error {{narrowing conversion}}
{ A<3> a{1, 2, 3, 4, 5, 6, 7, 8}; }
{ A<3> a = {1, 2, 3, 4, 5, 6, 7, 8}; }
{ A<3> a{1, 2, 3, 4, 5, 6, 7, 8}; }
{ A<3> a{1, 2}; }
+
+ { D<0> d{1, 2, 3}; }
+ { D<1> d{1.0, 2.0, 3.0}; }
+ { D<-1> d{1, 2.0}; } // expected-error {{ambiguous}}
+
+ { E<0> e{1, 2}; }
+ }
+
+ void explicit_implicit() {
+ { X1 x{0}; }
+ { X1 x = {0}; }
+ { X2 x{0}; }
+ { X2 x = {0}; } // expected-error {{explicit}}
}
struct C {
@@ -172,3 +201,28 @@ namespace litb {
B g({1, 2, 3});
}
+
+namespace aggregate {
+ // Direct list initialization does NOT allow braces to be elided!
+ struct S {
+ int ar[2];
+ struct T {
+ int i1;
+ int i2;
+ } t;
+ struct U {
+ int i1;
+ } u[2];
+ struct V {
+ int var[2];
+ } v;
+ };
+
+ void test() {
+ S s1 = { 1, 2, 3 ,4, 5, 6, 7, 8 }; // no-error
+ S s2{ {1, 2}, {3, 4}, { {5}, {6} }, { {7, 8} } }; // completely braced
+ S s3{ 1, 2, 3, 4, 5, 6 }; // xpected-error
+ S s4{ {1, 2}, {3, 4}, {5, 6}, { {7, 8} } }; // xpected-error
+ S s5{ {1, 2}, {3, 4}, { {5}, {6} }, {7, 8} }; // xpected-error
+ }
+}
diff --git a/test/SemaCXX/i-c-e-cxx.cpp b/test/SemaCXX/i-c-e-cxx.cpp
index 2d08ea9a428f..186e32126a39 100644
--- a/test/SemaCXX/i-c-e-cxx.cpp
+++ b/test/SemaCXX/i-c-e-cxx.cpp
@@ -42,3 +42,16 @@ namespace pr6206 {
void pr6373(const unsigned x = 0) {
unsigned max = 80 / x;
}
+
+
+// rdar://9204520
+namespace rdar9204520 {
+
+struct A {
+ static const int B = int(0.75 * 1000 * 1000);
+};
+
+int foo() { return A::B; }
+}
+
+
diff --git a/test/SemaCXX/member-init.cpp b/test/SemaCXX/member-init.cpp
index 1b8c523e4586..7ca1f0e4513e 100644
--- a/test/SemaCXX/member-init.cpp
+++ b/test/SemaCXX/member-init.cpp
@@ -48,3 +48,7 @@ struct CheckExcSpecFail {
CheckExcSpecFail() noexcept(true) = default; // expected-error {{exception specification of explicitly defaulted default constructor does not match the calculated one}}
ThrowCtor tc = 123;
};
+
+struct TypedefInit {
+ typedef int A = 0; // expected-error {{illegal initializer}}
+};
diff --git a/test/SemaCXX/member-pointer.cpp b/test/SemaCXX/member-pointer.cpp
index de3b211acf50..cf6481015a82 100644
--- a/test/SemaCXX/member-pointer.cpp
+++ b/test/SemaCXX/member-pointer.cpp
@@ -296,3 +296,19 @@ namespace PR9973 {
mem_fn(&test::nullary_v)(t); // expected-note{{in instantiation of}}
}
}
+
+namespace test8 {
+ struct A { int foo; };
+ int test1() {
+ // Verify that we perform (and check) an lvalue conversion on the operands here.
+ return (*((A**) 0)) // expected-warning {{indirection of non-volatile null pointer will be deleted}} expected-note {{consider}}
+ ->**(int A::**) 0; // expected-warning {{indirection of non-volatile null pointer will be deleted}} expected-note {{consider}}
+ }
+
+ int test2() {
+ // Verify that we perform (and check) an lvalue conversion on the operands here.
+ // TODO: the .* should itself warn about being a dereference of null.
+ return (*((A*) 0))
+ .**(int A::**) 0; // expected-warning {{indirection of non-volatile null pointer will be deleted}} expected-note {{consider}}
+ }
+}
diff --git a/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp b/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp
new file mode 100644
index 000000000000..fd0c976bdd78
--- /dev/null
+++ b/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp
@@ -0,0 +1,72 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-c++0x-extensions %s
+
+namespace fizbin { class Foobar; } // expected-note{{'fizbin::Foobar' declared here}}
+Foobar *my_bar = new Foobar; // expected-error{{unknown type name 'Foobar'; did you mean 'fizbin::Foobar'?}} \
+ // expected-error{{expected a type}}
+
+namespace barstool { int toFoobar() { return 1; } } // expected-note 3 {{'barstool::toFoobar' declared here}}
+int Double(int x) { return x + x; }
+void empty() {
+ Double(toFoobar()); // expected-error{{{use of undeclared identifier 'toFoobar'; did you mean 'barstool::toFoobar'?}}
+}
+
+namespace fizbin {
+ namespace baztool { bool toFoobar() { return true; } } // expected-note{{'fizbin::baztool' declared here}}
+ namespace nested { bool moreFoobar() { return true; } } // expected-note{{'fizbin::nested::moreFoobar' declared here}}
+ namespace nested { bool lessFoobar() { return true; } } // expected-note{{'fizbin::nested' declared here}} \
+ // expected-note{{'fizbin::nested::lessFoobar' declared here}}
+ class dummy { // expected-note 2 {{'fizbin::dummy' declared here}}
+ public:
+ static bool moreFoobar() { return false; } // expected-note{{'moreFoobar' declared here}}
+ };
+}
+void Check() { // expected-note{{'Check' declared here}}
+ if (toFoobar()) Double(7); // expected-error{{use of undeclared identifier 'toFoobar'; did you mean 'barstool::toFoobar'?}}
+ if (noFoobar()) Double(7); // expected-error{{use of undeclared identifier 'noFoobar'; did you mean 'barstool::toFoobar'?}}
+ if (moreFoobar()) Double(7); // expected-error{{use of undeclared identifier 'moreFoobar'; did you mean 'fizbin::nested::moreFoobar'}}
+ if (lessFoobar()) Double(7); // expected-error{{use of undeclared identifier 'lessFoobar'; did you mean 'fizbin::nested::lessFoobar'?}}
+ if (baztool::toFoobar()) Double(7); // expected-error{{use of undeclared identifier 'baztool'; did you mean 'fizbin::baztool'?}}
+ if (nested::moreFoobar()) Double(7); // expected-error{{use of undeclared identifier 'nested'; did you mean 'fizbin::nested'?}}
+ if (dummy::moreFoobar()) Double(7); // expected-error{{use of undeclared identifier 'dummy'; did you mean 'fizbin::dummy'?}}
+ if (dummy::mreFoobar()) Double(7); // expected-error{{use of undeclared identifier 'dummy'; did you mean 'fizbin::dummy'?}} \
+ // expected-error{{no member named 'mreFoobar' in 'fizbin::dummy'; did you mean 'moreFoobar'?}}
+ if (moFoobin()) Double(7); // expected-error{{use of undeclared identifier 'moFoobin'}}
+}
+
+void Alt() {
+ Cleck(); // expected-error{{{use of undeclared identifier 'Cleck'; did you mean 'Check'?}}
+}
+
+namespace N {
+ namespace inner {
+ class myvector { /* ... */ }; // expected-note{{'inner::myvector' declared here}}
+ }
+
+ void f() {
+ myvector v; // expected-error{{unknown type name 'myvector'; did you mean 'inner::myvector'?}}
+ }
+}
+
+namespace realstd {
+ inline namespace __1 {
+ class mylinkedlist { /* ... */ }; // expected-note 2 {{'realstd::mylinkedlist' declared here}}
+ }
+
+ class linkedlist { /* ... */ };
+}
+
+void f() {
+ mylinkedlist v; // expected-error{{unknown type name 'mylinkedlist'; did you mean 'realstd::mylinkedlist'?}}
+ nylinkedlist w; // expected-error{{unknown type name 'nylinkedlist'; did you mean 'realstd::mylinkedlist'?}}
+}
+
+// Test case from http://llvm.org/bugs/show_bug.cgi?id=10318
+namespace llvm {
+ template <typename T> class GraphWriter {}; // expected-note{{'llvm::GraphWriter' declared here}}
+}
+
+struct S {};
+void bar() {
+ GraphWriter<S> x; //expected-error{{no template named 'GraphWriter'; did you mean 'llvm::GraphWriter'?}}
+
+}
diff --git a/test/SemaCXX/nested-name-spec.cpp b/test/SemaCXX/nested-name-spec.cpp
index fef70931717e..ee6ca8857374 100644
--- a/test/SemaCXX/nested-name-spec.cpp
+++ b/test/SemaCXX/nested-name-spec.cpp
@@ -261,8 +261,27 @@ namespace PR8159 {
namespace rdar7980179 {
class A { void f0(); }; // expected-note {{previous}}
- int A::f0() {} // expected-error {{out-of-line definition of 'rdar7980179::A::f0' differ from the declaration in the return type}}
+ int A::f0() {} // expected-error {{out-of-line definition of 'rdar7980179::A::f0' differs from the declaration in the return type}}
}
namespace alias = A;
double *dp = (alias::C*)0; // expected-error{{cannot initialize a variable of type 'double *' with an rvalue of type 'alias::C *'}}
+
+// http://llvm.org/PR10109
+namespace PR10109 {
+template<typename T>
+struct A {
+protected:
+ struct B;
+ struct B::C; // expected-error {{requires a template parameter list}} \
+ // expected-error {{no struct named 'C'}}
+};
+
+template<typename T>
+struct A2 {
+protected:
+ struct B;
+};
+template <typename T>
+struct A2<T>::B::C; // expected-error {{no struct named 'C'}}
+}
diff --git a/test/SemaCXX/new-delete.cpp b/test/SemaCXX/new-delete.cpp
index 13ef461e7c0d..efdfa0f066db 100644
--- a/test/SemaCXX/new-delete.cpp
+++ b/test/SemaCXX/new-delete.cpp
@@ -389,3 +389,11 @@ namespace PR7702 {
new DoesNotExist; // expected-error {{expected a type}}
}
}
+
+namespace ArrayNewNeedsDtor {
+ struct A { A(); private: ~A(); }; // expected-note {{declared private here}}
+ struct B { B(); A a; }; // expected-error {{field of type 'ArrayNewNeedsDtor::A' has private destructor}}
+ B *test9() {
+ return new B[5]; // expected-note {{implicit default destructor for 'ArrayNewNeedsDtor::B' first required here}}
+ }
+}
diff --git a/test/SemaCXX/null_in_arithmetic_ops.cpp b/test/SemaCXX/null_in_arithmetic_ops.cpp
new file mode 100644
index 000000000000..fab6f10ab785
--- /dev/null
+++ b/test/SemaCXX/null_in_arithmetic_ops.cpp
@@ -0,0 +1,93 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsyntax-only -fblocks -Wnull-arithmetic -verify %s
+#include <stddef.h>
+
+void f() {
+ int a;
+ bool b;
+ void (^c)();
+ class X;
+ void (X::*d) ();
+ extern void e();
+ int f[2];
+ const void *v;
+
+ a = 0 ? NULL + a : a + NULL; // expected-warning 2{{use of NULL in arithmetic operation}}
+ a = 0 ? NULL - a : a - NULL; // expected-warning 2{{use of NULL in arithmetic operation}}
+ a = 0 ? NULL / a : a / NULL; // expected-warning 2{{use of NULL in arithmetic operation}} \
+ // expected-warning {{division by zero is undefined}}
+ a = 0 ? NULL * a : a * NULL; // expected-warning 2{{use of NULL in arithmetic operation}}
+ a = 0 ? NULL >> a : a >> NULL; // expected-warning 2{{use of NULL in arithmetic operation}}
+ a = 0 ? NULL << a : a << NULL; // expected-warning 2{{use of NULL in arithmetic operation}}
+ a = 0 ? NULL % a : a % NULL; // expected-warning 2{{use of NULL in arithmetic operation}} \
+ expected-warning {{remainder by zero is undefined}}
+ a = 0 ? NULL & a : a & NULL; // expected-warning 2{{use of NULL in arithmetic operation}}
+ a = 0 ? NULL | a : a | NULL; // expected-warning 2{{use of NULL in arithmetic operation}}
+ a = 0 ? NULL ^ a : a ^ NULL; // expected-warning 2{{use of NULL in arithmetic operation}}
+
+ // Check for warnings or errors when doing arithmetic on pointers and other
+ // types.
+ v = 0 ? NULL + &a : &a + NULL; // expected-warning 2{{use of NULL in arithmetic operation}}
+ v = 0 ? NULL + c : c + NULL; // \
+ expected-error {{invalid operands to binary expression ('long' and 'void (^)()')}} \
+ expected-error {{invalid operands to binary expression ('void (^)()' and 'long')}}
+ v = 0 ? NULL + d : d + NULL; // \
+ expected-error {{invalid operands to binary expression ('long' and 'void (X::*)()')}} \
+ expected-error {{invalid operands to binary expression ('void (X::*)()' and 'long')}}
+ v = 0 ? NULL + e : e + NULL; // expected-error 2{{arithmetic on a pointer to the function type 'void ()'}}
+ v = 0 ? NULL + f : f + NULL; // expected-warning 2{{use of NULL in arithmetic operation}}
+ v = 0 ? NULL + "f" : "f" + NULL; // expected-warning 2{{use of NULL in arithmetic operation}}
+
+ // Using two NULLs should only give one error instead of two.
+ a = NULL + NULL; // expected-warning{{use of NULL in arithmetic operation}}
+ a = NULL - NULL; // expected-warning{{use of NULL in arithmetic operation}}
+ a = NULL / NULL; // expected-warning{{use of NULL in arithmetic operation}} \
+ // expected-warning{{division by zero is undefined}}
+ a = NULL * NULL; // expected-warning{{use of NULL in arithmetic operation}}
+ a = NULL >> NULL; // expected-warning{{use of NULL in arithmetic operation}}
+ a = NULL << NULL; // expected-warning{{use of NULL in arithmetic operation}}
+ a = NULL % NULL; // expected-warning{{use of NULL in arithmetic operation}} \
+ // expected-warning{{remainder by zero is undefined}}
+ a = NULL & NULL; // expected-warning{{use of NULL in arithmetic operation}}
+ a = NULL | NULL; // expected-warning{{use of NULL in arithmetic operation}}
+ a = NULL ^ NULL; // expected-warning{{use of NULL in arithmetic operation}}
+
+ a += NULL; // expected-warning{{use of NULL in arithmetic operation}}
+ a -= NULL; // expected-warning{{use of NULL in arithmetic operation}}
+ a /= NULL; // expected-warning{{use of NULL in arithmetic operation}} \
+ // expected-warning{{division by zero is undefined}}
+ a *= NULL; // expected-warning{{use of NULL in arithmetic operation}}
+ a >>= NULL; // expected-warning{{use of NULL in arithmetic operation}}
+ a <<= NULL; // expected-warning{{use of NULL in arithmetic operation}}
+ a %= NULL; // expected-warning{{use of NULL in arithmetic operation}} \
+ // expected-warning{{remainder by zero is undefined}}
+ a &= NULL; // expected-warning{{use of NULL in arithmetic operation}}
+ a |= NULL; // expected-warning{{use of NULL in arithmetic operation}}
+ a ^= NULL; // expected-warning{{use of NULL in arithmetic operation}}
+
+ b = a < NULL || NULL < a; // expected-warning 2{{use of NULL in arithmetic operation}}
+ b = a > NULL || NULL > a; // expected-warning 2{{use of NULL in arithmetic operation}}
+ b = a <= NULL || NULL <= a; // expected-warning 2{{use of NULL in arithmetic operation}}
+ b = a >= NULL || NULL >= a; // expected-warning 2{{use of NULL in arithmetic operation}}
+ b = a == NULL || NULL == a; // expected-warning 2{{use of NULL in arithmetic operation}}
+ b = a != NULL || NULL != a; // expected-warning 2{{use of NULL in arithmetic operation}}
+
+ b = &a < NULL || NULL < &a || &a > NULL || NULL > &a;
+ b = &a <= NULL || NULL <= &a || &a >= NULL || NULL >= &a;
+ b = &a == NULL || NULL == &a || &a != NULL || NULL != &a;
+
+ b = 0 == a;
+ b = 0 == &a;
+
+ b = NULL < NULL || NULL > NULL;
+ b = NULL <= NULL || NULL >= NULL;
+ b = NULL == NULL || NULL != NULL;
+
+ b = ((NULL)) != a; // expected-warning{{use of NULL in arithmetic operation}}
+
+ // Check that even non-standard pointers don't warn.
+ b = c == NULL || NULL == c || c != NULL || NULL != c;
+ b = d == NULL || NULL == d || d != NULL || NULL != d;
+ b = e == NULL || NULL == e || e != NULL || NULL != e;
+ b = f == NULL || NULL == f || f != NULL || NULL != f;
+ b = "f" == NULL || NULL == "f" || "f" != NULL || NULL != "f";
+}
diff --git a/test/SemaCXX/nullptr_in_arithmetic_ops.cpp b/test/SemaCXX/nullptr_in_arithmetic_ops.cpp
new file mode 100644
index 000000000000..e839ed116f8d
--- /dev/null
+++ b/test/SemaCXX/nullptr_in_arithmetic_ops.cpp
@@ -0,0 +1,73 @@
+// RUN: %clang_cc1 -fsyntax-only -fblocks -std=c++0x -verify %s
+
+void foo() {
+ int a;
+ bool b;
+
+ a = 0 ? nullptr + a : a + nullptr; // expected-error 2{{invalid operands to binary expression}}
+ a = 0 ? nullptr - a : a - nullptr; // expected-error 2{{invalid operands to binary expression}}
+ a = 0 ? nullptr / a : a / nullptr; // expected-error 2{{invalid operands to binary expression}}
+ a = 0 ? nullptr * a : a * nullptr; // expected-error 2{{invalid operands to binary expression}}
+ a = 0 ? nullptr >> a : a >> nullptr; // expected-error 2{{invalid operands to binary expression}}
+ a = 0 ? nullptr << a : a << nullptr; // expected-error 2{{invalid operands to binary expression}}
+ a = 0 ? nullptr % a : a % nullptr; // expected-error 2{{invalid operands to binary expression}}
+ a = 0 ? nullptr & a : a & nullptr; // expected-error 2{{invalid operands to binary expression}}
+ a = 0 ? nullptr | a : a | nullptr; // expected-error 2{{invalid operands to binary expression}}
+ a = 0 ? nullptr ^ a : a ^ nullptr; // expected-error 2{{invalid operands to binary expression}}
+
+ // Using two nullptrs should only give one error instead of two.
+ a = nullptr + nullptr; // expected-error{{invalid operands to binary expression}}
+ a = nullptr - nullptr; // expected-error{{invalid operands to binary expression}}
+ a = nullptr / nullptr; // expected-error{{invalid operands to binary expression}}
+ a = nullptr * nullptr; // expected-error{{invalid operands to binary expression}}
+ a = nullptr >> nullptr; // expected-error{{invalid operands to binary expression}}
+ a = nullptr << nullptr; // expected-error{{invalid operands to binary expression}}
+ a = nullptr % nullptr; // expected-error{{invalid operands to binary expression}}
+ a = nullptr & nullptr; // expected-error{{invalid operands to binary expression}}
+ a = nullptr | nullptr; // expected-error{{invalid operands to binary expression}}
+ a = nullptr ^ nullptr; // expected-error{{invalid operands to binary expression}}
+
+ a += nullptr; // expected-error{{invalid operands to binary expression}}
+ a -= nullptr; // expected-error{{invalid operands to binary expression}}
+ a /= nullptr; // expected-error{{invalid operands to binary expression}}
+ a *= nullptr; // expected-error{{invalid operands to binary expression}}
+ a >>= nullptr; // expected-error{{invalid operands to binary expression}}
+ a <<= nullptr; // expected-error{{invalid operands to binary expression}}
+ a %= nullptr; // expected-error{{invalid operands to binary expression}}
+ a &= nullptr; // expected-error{{invalid operands to binary expression}}
+ a |= nullptr; // expected-error{{invalid operands to binary expression}}
+ a ^= nullptr; // expected-error{{invalid operands to binary expression}}
+
+ b = a < nullptr || nullptr < a; // expected-error 2{{invalid operands to binary expression}}
+ b = a > nullptr || nullptr > a; // expected-error 2{{invalid operands to binary expression}}
+ b = a <= nullptr || nullptr <= a; // expected-error 2{{invalid operands to binary expression}}
+ b = a >= nullptr || nullptr >= a; // expected-error 2{{invalid operands to binary expression}}
+ b = a == nullptr || nullptr == a; // expected-error 2{{invalid operands to binary expression}}
+ b = a != nullptr || nullptr != a; // expected-error 2{{invalid operands to binary expression}}
+
+ b = &a < nullptr || nullptr < &a || &a > nullptr || nullptr > &a;
+ b = &a <= nullptr || nullptr <= &a || &a >= nullptr || nullptr >= &a;
+ b = &a == nullptr || nullptr == &a || &a != nullptr || nullptr != &a;
+
+ b = nullptr < nullptr || nullptr > nullptr;
+ b = nullptr <= nullptr || nullptr >= nullptr;
+ b = nullptr == nullptr || nullptr != nullptr;
+
+ b = ((nullptr)) != a; // expected-error{{invalid operands to binary expression}}
+
+ void (^c)();
+ c = nullptr;
+ b = c == nullptr || nullptr == c || c != nullptr || nullptr != c;
+
+ class X;
+ void (X::*d) ();
+ d = nullptr;
+ b = d == nullptr || nullptr == d || d != nullptr || nullptr != d;
+
+ extern void e();
+ b = e == nullptr || nullptr == e || e != nullptr || nullptr != e;
+
+ int f[2];
+ b = f == nullptr || nullptr == f || f != nullptr || nullptr != f;
+ b = "f" == nullptr || nullptr == "f" || "f" != nullptr || nullptr != "f";
+}
diff --git a/test/SemaCXX/overloaded-name.cpp b/test/SemaCXX/overloaded-name.cpp
index 5a87cc8e67e6..73f12a902723 100644
--- a/test/SemaCXX/overloaded-name.cpp
+++ b/test/SemaCXX/overloaded-name.cpp
@@ -12,3 +12,19 @@ void test(bool b) {
(void)(b? ovl<float> : &ovl); // expected-error{{cannot resolve overloaded function 'ovl' from context}}
(void)(b? ovl<float> : ovl<float>);
}
+
+namespace rdar9623945 {
+ void f(...) {
+ }
+
+ class X {
+ public:
+ const char* text(void);
+ void g(void) {
+ f(text());
+ f(text); // expected-error{{a bound member function may only be called}}
+ f(text());
+ f(text); // expected-error{{a bound member function may only be called}}
+ }
+ };
+}
diff --git a/test/SemaCXX/return.cpp b/test/SemaCXX/return.cpp
index b457f6ace55a..2f98a277f638 100644
--- a/test/SemaCXX/return.cpp
+++ b/test/SemaCXX/return.cpp
@@ -69,3 +69,14 @@ namespace PR10057 {
return S() = value;
}
}
+
+namespace return_has_expr {
+ struct S {
+ S() {
+ return 42; // expected-error {{constructor 'S' should not return a value}}
+ }
+ ~S() {
+ return 42; // expected-error {{destructor '~S' should not return a value}}
+ }
+ };
+}
diff --git a/test/SemaCXX/vararg-non-pod.cpp b/test/SemaCXX/vararg-non-pod.cpp
index df0080fac94a..3ca07b0215c3 100644
--- a/test/SemaCXX/vararg-non-pod.cpp
+++ b/test/SemaCXX/vararg-non-pod.cpp
@@ -101,3 +101,21 @@ void t6(Foo somearg, ... ) {
__builtin_va_start(list, somearg);
}
+void t7(int n, ...) {
+ __builtin_va_list list;
+ __builtin_va_start(list, n);
+ (void)__builtin_va_arg(list, C); // expected-warning{{second argument to 'va_arg' is of non-POD type 'C'}}
+ __builtin_va_end(list);
+}
+
+struct Abstract {
+ virtual void doit() = 0; // expected-note{{unimplemented pure virtual method}}
+};
+
+void t8(int n, ...) {
+ __builtin_va_list list;
+ __builtin_va_start(list, n);
+ (void)__builtin_va_arg(list, Abstract); // expected-error{{second argument to 'va_arg' is of abstract type 'Abstract'}}
+ __builtin_va_end(list);
+}
+
diff --git a/test/SemaCXX/vector.cpp b/test/SemaCXX/vector.cpp
index 9ae2c82fc530..4d3d93974c16 100644
--- a/test/SemaCXX/vector.cpp
+++ b/test/SemaCXX/vector.cpp
@@ -176,10 +176,10 @@ void test_implicit_conversions(bool Cond, char16 c16, longlong16 ll16,
(void)(to_c16 * to_c16e);
(void)(to_c16 / to_c16e);
(void)(rto_c16 = c16e); // expected-error{{no viable overloaded '='}}
- (void)(rto_c16 += to_c16e); // expected-error{{expression is not assignable}}
- (void)(rto_c16 -= to_c16e); // expected-error{{expression is not assignable}}
- (void)(rto_c16 *= to_c16e); // expected-error{{expression is not assignable}}
- (void)(rto_c16 /= to_c16e); // expected-error{{expression is not assignable}}
+ (void)(rto_c16 += to_c16e);
+ (void)(rto_c16 -= to_c16e);
+ (void)(rto_c16 *= to_c16e);
+ (void)(rto_c16 /= to_c16e);
(void)(Cond? to_c16 : to_c16e);
(void)(Cond? to_ll16e : to_ll16);
diff --git a/test/SemaCXX/virtuals.cpp b/test/SemaCXX/virtuals.cpp
index 792467e5f86b..d8c26efcfb42 100644
--- a/test/SemaCXX/virtuals.cpp
+++ b/test/SemaCXX/virtuals.cpp
@@ -1,8 +1,8 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -verify -std=c++0x %s
class A {
virtual void f();
- virtual void g() = 0;
+ virtual void g() = 0; // expected-note{{unimplemented pure virtual method 'g' in 'A'}}
void h() = 0; // expected-error {{'h' is not virtual and cannot be declared pure}}
void i() = 1; // expected-error {{initializer on function does not look like a pure-specifier}}
@@ -19,20 +19,29 @@ virtual void A::k() { } // expected-error{{'virtual' can only be specified insid
class B : public A {
// Needs to recognize that overridden function is virtual.
- //void g() = 0;
+ void g() = 0;
// Needs to recognize that function does not override.
- //void g(int) = 0;
+ void g(int) = 0; // expected-error{{'g' is not virtual and cannot be declared pure}}
};
// Needs to recognize invalid uses of abstract classes.
-/*
-A fn(A)
+A fn(A) // expected-error{{parameter type 'A' is an abstract class}} \
+ // expected-error{{return type 'A' is an abstract class}}
{
- A a;
- static_cast<A>(0);
+ A a; // expected-error{{variable type 'A' is an abstract class}}
+ (void)static_cast<A>(0);
try {
- } catch(A) {
+ } catch(A) { // expected-error{{variable type 'A' is an abstract class}}
}
}
-*/
+
+namespace rdar9670557 {
+ typedef int func(int);
+ func *a();
+ struct X {
+ virtual func f = 0;
+ virtual func (g) = 0;
+ func *h = 0;
+ };
+}
diff --git a/test/SemaCXX/warn-bad-memaccess.cpp b/test/SemaCXX/warn-bad-memaccess.cpp
index e7d095f0edce..9a998f020cb4 100644
--- a/test/SemaCXX/warn-bad-memaccess.cpp
+++ b/test/SemaCXX/warn-bad-memaccess.cpp
@@ -38,6 +38,46 @@ void test_warn() {
memcpy(0, &x1, sizeof x1); // \
// expected-warning{{source of this 'memcpy' call is a pointer to dynamic class}} \
// expected-note {{explicitly cast the pointer to silence this warning}}
+
+ __builtin_memset(&x1, 0, sizeof x1); // \
+ // expected-warning {{destination for this '__builtin_memset' call is a pointer to dynamic class}} \
+ // expected-note {{explicitly cast the pointer to silence this warning}}
+ __builtin_memset(&x2, 0, sizeof x2); // \
+ // expected-warning {{destination for this '__builtin_memset' call is a pointer to dynamic class}} \
+ // expected-note {{explicitly cast the pointer to silence this warning}}
+
+ __builtin_memmove(&x1, 0, sizeof x1); // \
+ // expected-warning{{destination for this '__builtin_memmove' call is a pointer to dynamic class}} \
+ // expected-note {{explicitly cast the pointer to silence this warning}}
+ __builtin_memmove(0, &x1, sizeof x1); // \
+ // expected-warning{{source of this '__builtin_memmove' call is a pointer to dynamic class}} \
+ // expected-note {{explicitly cast the pointer to silence this warning}}
+ __builtin_memcpy(&x1, 0, sizeof x1); // \
+ // expected-warning{{destination for this '__builtin_memcpy' call is a pointer to dynamic class}} \
+ // expected-note {{explicitly cast the pointer to silence this warning}}
+ __builtin_memcpy(0, &x1, sizeof x1); // \
+ // expected-warning{{source of this '__builtin_memcpy' call is a pointer to dynamic class}} \
+ // expected-note {{explicitly cast the pointer to silence this warning}}
+
+ __builtin___memset_chk(&x1, 0, sizeof x1, sizeof x1); // \
+ // expected-warning {{destination for this '__builtin___memset_chk' call is a pointer to dynamic class}} \
+ // expected-note {{explicitly cast the pointer to silence this warning}}
+ __builtin___memset_chk(&x2, 0, sizeof x2, sizeof x2); // \
+ // expected-warning {{destination for this '__builtin___memset_chk' call is a pointer to dynamic class}} \
+ // expected-note {{explicitly cast the pointer to silence this warning}}
+
+ __builtin___memmove_chk(&x1, 0, sizeof x1, sizeof x1); // \
+ // expected-warning{{destination for this '__builtin___memmove_chk' call is a pointer to dynamic class}} \
+ // expected-note {{explicitly cast the pointer to silence this warning}}
+ __builtin___memmove_chk(0, &x1, sizeof x1, sizeof x1); // \
+ // expected-warning{{source of this '__builtin___memmove_chk' call is a pointer to dynamic class}} \
+ // expected-note {{explicitly cast the pointer to silence this warning}}
+ __builtin___memcpy_chk(&x1, 0, sizeof x1, sizeof x1); // \
+ // expected-warning{{destination for this '__builtin___memcpy_chk' call is a pointer to dynamic class}} \
+ // expected-note {{explicitly cast the pointer to silence this warning}}
+ __builtin___memcpy_chk(0, &x1, sizeof x1, sizeof x1); // \
+ // expected-warning{{source of this '__builtin___memcpy_chk' call is a pointer to dynamic class}} \
+ // expected-note {{explicitly cast the pointer to silence this warning}}
}
void test_nowarn(void *void_ptr) {
@@ -68,3 +108,5 @@ namespace N {
N::memset(&x1, 0, sizeof x1);
}
}
+
+
diff --git a/test/SemaCXX/warn-memset-bad-sizeof.cpp b/test/SemaCXX/warn-memset-bad-sizeof.cpp
new file mode 100644
index 000000000000..90ac50472e98
--- /dev/null
+++ b/test/SemaCXX/warn-memset-bad-sizeof.cpp
@@ -0,0 +1,101 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-sizeof-array-argument %s
+//
+extern "C" void *memset(void *, int, unsigned);
+extern "C" void *memmove(void *s1, const void *s2, unsigned n);
+extern "C" void *memcpy(void *s1, const void *s2, unsigned n);
+
+struct S {int a, b, c, d;};
+typedef S* PS;
+
+struct Foo {};
+typedef const Foo& CFooRef;
+typedef const Foo CFoo;
+typedef volatile Foo VFoo;
+typedef const volatile Foo CVFoo;
+
+typedef double Mat[4][4];
+
+template <class Dest, class Source>
+inline Dest bit_cast(const Source& source) {
+ Dest dest;
+ memcpy(&dest, &source, sizeof(dest));
+ return dest;
+}
+
+// http://www.lysator.liu.se/c/c-faq/c-2.html#2-6
+void f(Mat m, const Foo& const_foo, char *buffer) {
+ S s;
+ S* ps = &s;
+ PS ps2 = &s;
+ char arr[5];
+ char* parr[5];
+ Foo foo;
+ char* heap_buffer = new char[42];
+
+ /* Should warn */
+ memset(&s, 0, sizeof(&s)); // \
+ // expected-warning {{argument to 'sizeof' in 'memset' call is the same expression as the destination}}
+ memset(ps, 0, sizeof(ps)); // \
+ // expected-warning {{argument to 'sizeof' in 'memset' call is the same expression as the destination}}
+ memset(ps2, 0, sizeof(ps2)); // \
+ // expected-warning {{argument to 'sizeof' in 'memset' call is the same expression as the destination}}
+ memset(ps2, 0, sizeof(typeof(ps2))); // \
+ // expected-warning {{argument to 'sizeof' in 'memset' call is the same pointer type}}
+ memset(ps2, 0, sizeof(PS)); // \
+ // expected-warning {{argument to 'sizeof' in 'memset' call is the same pointer type}}
+ memset(heap_buffer, 0, sizeof(heap_buffer)); // \
+ // expected-warning {{argument to 'sizeof' in 'memset' call is the same expression as the destination}}
+
+ memcpy(&s, 0, sizeof(&s)); // \
+ // expected-warning {{argument to 'sizeof' in 'memcpy' call is the same expression as the destination}}
+ memcpy(0, &s, sizeof(&s)); // \
+ // expected-warning {{argument to 'sizeof' in 'memcpy' call is the same expression as the source}}
+
+ /* Shouldn't warn */
+ memset((void*)&s, 0, sizeof(&s));
+ memset(&s, 0, sizeof(s));
+ memset(&s, 0, sizeof(S));
+ memset(&s, 0, sizeof(const S));
+ memset(&s, 0, sizeof(volatile S));
+ memset(&s, 0, sizeof(volatile const S));
+ memset(&foo, 0, sizeof(CFoo));
+ memset(&foo, 0, sizeof(VFoo));
+ memset(&foo, 0, sizeof(CVFoo));
+ memset(ps, 0, sizeof(*ps));
+ memset(ps2, 0, sizeof(*ps2));
+ memset(ps2, 0, sizeof(typeof(*ps2)));
+ memset(arr, 0, sizeof(arr));
+ memset(parr, 0, sizeof(parr));
+
+ memcpy(&foo, &const_foo, sizeof(Foo));
+ memcpy((void*)&s, 0, sizeof(&s));
+ memcpy(0, (void*)&s, sizeof(&s));
+ char *cptr;
+ memcpy(&cptr, buffer, sizeof(cptr));
+ memcpy((char*)&cptr, buffer, sizeof(cptr));
+
+ CFooRef cfoo = foo;
+ memcpy(&foo, &cfoo, sizeof(Foo));
+
+ memcpy(0, &arr, sizeof(arr));
+ typedef char Buff[8];
+ memcpy(0, &arr, sizeof(Buff));
+
+ unsigned char* puc;
+ bit_cast<char*>(puc);
+
+ float* pf;
+ bit_cast<int*>(pf);
+
+ int iarr[14];
+ memset(&iarr[0], 0, sizeof iarr);
+
+ int* iparr[14];
+ memset(&iparr[0], 0, sizeof iparr);
+
+ memset(m, 0, sizeof(Mat));
+
+ // Copy to raw buffer shouldn't warn either
+ memcpy(&foo, &arr, sizeof(Foo));
+ memcpy(&arr, &foo, sizeof(Foo));
+}
diff --git a/test/SemaCXX/warn-pure-virtual-call-from-ctor-dtor.cpp b/test/SemaCXX/warn-pure-virtual-call-from-ctor-dtor.cpp
index 698eccd1d2f0..ade6198fbd0d 100644
--- a/test/SemaCXX/warn-pure-virtual-call-from-ctor-dtor.cpp
+++ b/test/SemaCXX/warn-pure-virtual-call-from-ctor-dtor.cpp
@@ -5,3 +5,10 @@ struct A {
virtual void f() = 0; // expected-note 2 {{'f' declared here}}
};
+
+// Don't warn (or note) when calling the function on a pointer. (PR10195)
+struct B {
+ A *a;
+ B() { a->f(); };
+ ~B() { a->f(); };
+};
diff --git a/test/SemaCXX/warn-unused-variables.cpp b/test/SemaCXX/warn-unused-variables.cpp
index 81f22a796a0e..5ba1f2a5f34b 100644
--- a/test/SemaCXX/warn-unused-variables.cpp
+++ b/test/SemaCXX/warn-unused-variables.cpp
@@ -54,3 +54,29 @@ void unused_local_static() {
static int y = 0; // expected-warning{{unused variable 'y'}}
#pragma unused(x)
}
+
+// PR10168
+namespace PR10168 {
+ // We expect a warning in the definition only for non-dependent variables, and
+ // a warning in the instantiation only for dependent variables.
+ template<typename T>
+ struct S {
+ void f() {
+ int a; // expected-warning {{unused variable 'a'}}
+ T b; // expected-warning 2{{unused variable 'b'}}
+ }
+ };
+
+ template<typename T>
+ void f() {
+ int a; // expected-warning {{unused variable 'a'}}
+ T b; // expected-warning 2{{unused variable 'b'}}
+ }
+
+ void g() {
+ S<int>().f(); // expected-note {{here}}
+ S<char>().f(); // expected-note {{here}}
+ f<int>(); // expected-note {{here}}
+ f<char>(); // expected-note {{here}}
+ }
+}
diff --git a/test/SemaObjC/Inputs/arc-system-header.h b/test/SemaObjC/Inputs/arc-system-header.h
new file mode 100644
index 000000000000..5012a2a37837
--- /dev/null
+++ b/test/SemaObjC/Inputs/arc-system-header.h
@@ -0,0 +1,52 @@
+static inline void *test0(id x) {
+ return x;
+}
+
+static inline void **test1(__strong id* x) {
+ return (void**) x;
+}
+
+
+
+
+
+struct Test3 {
+ id *field;
+};
+
+@interface Test4 {
+@public
+ id *field1;
+ __strong id *field2;
+}
+@end
+
+struct Test5 {
+ id field;
+};
+
+
+
+
+
+
+
+extern struct Test6 *const kMagicConstant;
+
+
+
+
+
+@interface Test7
+@property id *prop;
+@end
+
+
+
+
+
+
+
+static inline void *test8(id ptr) {
+ return (__bridge_retain void*) ptr;
+}
diff --git a/test/SemaObjC/arc-bridged-cast.m b/test/SemaObjC/arc-bridged-cast.m
new file mode 100644
index 000000000000..e883406db908
--- /dev/null
+++ b/test/SemaObjC/arc-bridged-cast.m
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -fblocks -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fsyntax-only -fblocks %s
+
+typedef const void *CFTypeRef;
+typedef const struct __CFString *CFStringRef;
+
+@interface NSString
+@end
+
+CFTypeRef CFCreateSomething();
+CFStringRef CFCreateString();
+CFTypeRef CFGetSomething();
+CFStringRef CFGetString();
+
+id CreateSomething();
+NSString *CreateNSString();
+
+void from_cf() {
+ id obj1 = (__bridge_transfer id)CFCreateSomething();
+ id obj2 = (__bridge_transfer NSString*)CFCreateString();
+ (__bridge int*)CFCreateSomething(); // expected-error{{incompatible types casting 'CFTypeRef' (aka 'const void *') to 'int *' with a __bridge cast}}
+ id obj3 = (__bridge id)CFGetSomething();
+ id obj4 = (__bridge NSString*)CFGetString();
+}
+
+void to_cf(id obj) {
+ CFTypeRef cf1 = (__bridge_retained CFTypeRef)CreateSomething();
+ CFStringRef cf2 = (__bridge_retained CFStringRef)CreateNSString();
+ CFTypeRef cf3 = (__bridge CFTypeRef)CreateSomething();
+ CFStringRef cf4 = (__bridge CFStringRef)CreateNSString();
+
+ // rdar://problem/9629566 - temporary workaround
+ CFTypeRef cf5 = (__bridge_retain CFTypeRef)CreateSomething(); // expected-error {{unknown cast annotation __bridge_retain; did you mean __bridge_retained?}}
+}
+
+void fixits() {
+ id obj1 = (id)CFCreateSomething(); // expected-error{{cast of C pointer type 'CFTypeRef' (aka 'const void *') to Objective-C pointer type 'id' requires a bridged cast}} \
+ // expected-note{{use __bridge to convert directly (no change in ownership)}} \
+ // expected-note{{use __bridge_transfer to transfer ownership of a +1 'CFTypeRef' (aka 'const void *') into ARC}}
+ CFTypeRef cf1 = (CFTypeRef)CreateSomething(); // expected-error{{cast of Objective-C pointer type 'id' to C pointer type 'CFTypeRef' (aka 'const void *') requires a bridged cast}} \
+ // expected-note{{use __bridge to convert directly (no change in ownership)}} \
+ // expected-note{{use __bridge_retained to make an ARC object available as a +1 'CFTypeRef' (aka 'const void *')}}
+}
diff --git a/test/SemaObjC/arc-decls.m b/test/SemaObjC/arc-decls.m
new file mode 100644
index 000000000000..e713d239a0cf
--- /dev/null
+++ b/test/SemaObjC/arc-decls.m
@@ -0,0 +1,64 @@
+// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -fobjc-nonfragile-abi -verify %s
+
+// rdar://8843524
+
+struct A {
+ id x; // expected-error {{ARC forbids Objective-C objects in structs or unions}}
+};
+
+union u {
+ id u; // expected-error {{ARC forbids Objective-C objects in structs or unions}}
+};
+
+@interface I {
+ struct A a;
+ struct B {
+ id y[10][20]; // expected-error {{ARC forbids Objective-C objects in structs or unions}}
+ id z;
+ } b;
+
+ union u c;
+};
+@end
+
+struct S {
+ id __attribute__((objc_ownership(none))) i;
+ void * vp;
+ int i1;
+};
+
+// rdar://9046528
+
+@class NSError;
+
+__autoreleasing id X; // expected-error {{global variables cannot have __autoreleasing ownership}}
+__autoreleasing NSError *E; // expected-error {{global variables cannot have __autoreleasing ownership}}
+
+
+extern id __autoreleasing X1; // expected-error {{global variables cannot have __autoreleasing ownership}}
+
+void func()
+{
+ id X;
+ static id __autoreleasing X1; // expected-error {{global variables cannot have __autoreleasing ownership}}
+ extern id __autoreleasing E; // expected-error {{global variables cannot have __autoreleasing ownership}}
+
+}
+
+// rdar://9157348
+
+@interface J
+@property (retain) id newFoo; // expected-note {{property declared here}}
+@property (strong) id copyBar; // expected-note {{property declared here}}
+@property (copy) id allocBaz; // expected-note {{property declared here}}
+@property (copy, nonatomic) id new;
+@end
+
+@implementation J
+@synthesize newFoo; // expected-error {{property's synthesized getter follows Cocoa naming convention for returning}}
+@synthesize copyBar; // expected-error {{property's synthesized getter follows Cocoa naming convention for returning}}
+@synthesize allocBaz; // expected-error {{property's synthesized getter follows Cocoa naming convention for returning}}
+@synthesize new;
+- new {return 0; };
+@end
+
diff --git a/test/SemaObjC/arc-jump-block.m b/test/SemaObjC/arc-jump-block.m
new file mode 100644
index 000000000000..1c7b21e4e8cd
--- /dev/null
+++ b/test/SemaObjC/arc-jump-block.m
@@ -0,0 +1,84 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -fblocks -verify %s
+// rdar://9535237
+
+typedef struct dispatch_queue_s *dispatch_queue_t;
+
+typedef void (^dispatch_block_t)(void);
+
+void dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
+
+extern __attribute__((visibility("default"))) struct dispatch_queue_s _dispatch_main_q;
+
+@interface SwitchBlockCrashAppDelegate
+- (void)pageLeft;
+- (void)pageRight;;
+@end
+
+@implementation SwitchBlockCrashAppDelegate
+
+- (void)choose:(int)button {
+ switch (button) {
+ case 0:
+ dispatch_async((&_dispatch_main_q), ^{ [self pageLeft]; }); // expected-note 3 {{jump enters lifetime of block which strongly captures a variable}}
+ break;
+ case 2: // expected-error {{switch case is in protected scope}}
+ dispatch_async((&_dispatch_main_q), ^{ [self pageRight]; }); // expected-note 2 {{jump enters lifetime of block which strongly captures a variable}}
+ break;
+ case 3: // expected-error {{switch case is in protected scope}}
+ {
+ dispatch_async((&_dispatch_main_q), ^{ [self pageRight]; });
+ break;
+ }
+ case 4: // expected-error {{switch case is in protected scope}}
+ break;
+ }
+
+ __block SwitchBlockCrashAppDelegate *captured_block_obj;
+ switch (button) {
+ case 10:
+ {
+ dispatch_async((&_dispatch_main_q), ^{ [self pageLeft]; });
+ break;
+ }
+ case 12:
+ if (button)
+ dispatch_async((&_dispatch_main_q), ^{ [captured_block_obj pageRight]; });
+ break;
+ case 13:
+ while (button)
+ dispatch_async((&_dispatch_main_q), ^{ [self pageRight]; });
+ break;
+ case 14:
+ break;
+ }
+
+ switch (button) {
+ case 10:
+ {
+ dispatch_async((&_dispatch_main_q), ^{ [self pageLeft]; });
+ break;
+ }
+ case 12:
+ if (button)
+ dispatch_async((&_dispatch_main_q), ^{ [self pageRight]; });
+ switch (button) {
+ case 0:
+ {
+ dispatch_async((&_dispatch_main_q), ^{ [self pageLeft]; });
+ break;
+ }
+ case 4:
+ break;
+ }
+ break;
+ case 13:
+ while (button)
+ dispatch_async((&_dispatch_main_q), ^{ [self pageRight]; });
+ break;
+ case 14:
+ break;
+ }
+}
+- (void)pageLeft {}
+- (void)pageRight {}
+@end
diff --git a/test/SemaObjC/arc-no-runtime.m b/test/SemaObjC/arc-no-runtime.m
new file mode 100644
index 000000000000..94299e235e81
--- /dev/null
+++ b/test/SemaObjC/arc-no-runtime.m
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fobjc-arc -fobjc-nonfragile-abi -verify %s
+
+// rdar://problem/9150784
+void test(void) {
+ __weak id x; // expected-error {{the current deployment target does not support automated __weak references}}
+}
+
+@interface A
+@property (weak) id testObjectWeakProperty; // expected-note {{declared here}}
+@end
+
+@implementation A
+// rdar://9605088
+@synthesize testObjectWeakProperty; // expected-error {{the current deployment target does not support automated __weak references}}
+@end
diff --git a/test/SemaObjC/arc-non-pod-memaccess.m b/test/SemaObjC/arc-non-pod-memaccess.m
new file mode 100644
index 000000000000..c9a77519694d
--- /dev/null
+++ b/test/SemaObjC/arc-non-pod-memaccess.m
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -fobjc-runtime-has-weak -verify -fblocks -triple x86_64-apple-darwin10.0.0 %s
+// RUN: %clang_cc1 -x objective-c++ -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -fobjc-runtime-has-weak -verify -fblocks -triple x86_64-apple-darwin10.0.0 %s
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void *memset(void *, int, __SIZE_TYPE__);
+void *memmove(void *s1, const void *s2, __SIZE_TYPE__ n);
+void *memcpy(void *s1, const void *s2, __SIZE_TYPE__ n);
+
+#ifdef __cplusplus
+}
+#endif
+
+void test(id __strong *sip, id __weak *wip, id __autoreleasing *aip,
+ id __unsafe_unretained *uip, void *ptr) {
+ // All okay.
+ memset(sip, 0, 17);
+ memset(wip, 0, 17);
+ memset(aip, 0, 17);
+ memset(uip, 0, 17);
+
+ memcpy(sip, ptr, 17); // expected-warning{{destination for this 'memcpy' call is a pointer to ownership-qualified type}} \
+ // expected-note{{explicitly cast the pointer to silence this warning}}
+ memcpy(wip, ptr, 17); // expected-warning{{destination for this 'memcpy' call is a pointer to ownership-qualified type}} \
+ // expected-note{{explicitly cast the pointer to silence this warning}}
+ memcpy(aip, ptr, 17); // expected-warning{{destination for this 'memcpy' call is a pointer to ownership-qualified type}} \
+ // expected-note{{explicitly cast the pointer to silence this warning}}
+ memcpy(uip, ptr, 17);
+
+ memcpy(ptr, sip, 17); // expected-warning{{source of this 'memcpy' call is a pointer to ownership-qualified type}} \
+ // expected-note{{explicitly cast the pointer to silence this warning}}
+ memcpy(ptr, wip, 17); // expected-warning{{source of this 'memcpy' call is a pointer to ownership-qualified type}} \
+ // expected-note{{explicitly cast the pointer to silence this warning}}
+ memcpy(ptr, aip, 17); // expected-warning{{source of this 'memcpy' call is a pointer to ownership-qualified type}} \
+ // expected-note{{explicitly cast the pointer to silence this warning}}
+ memcpy(ptr, uip, 17);
+
+ memmove(sip, ptr, 17); // expected-warning{{destination for this 'memmove' call is a pointer to ownership-qualified type}} \
+ // expected-note{{explicitly cast the pointer to silence this warning}}
+ memmove(wip, ptr, 17); // expected-warning{{destination for this 'memmove' call is a pointer to ownership-qualified type}} \
+ // expected-note{{explicitly cast the pointer to silence this warning}}
+ memmove(aip, ptr, 17); // expected-warning{{destination for this 'memmove' call is a pointer to ownership-qualified type}} \
+ // expected-note{{explicitly cast the pointer to silence this warning}}
+ memmove(uip, ptr, 17);
+
+ memmove(ptr, sip, 17); // expected-warning{{source of this 'memmove' call is a pointer to ownership-qualified type}} \
+ // expected-note{{explicitly cast the pointer to silence this warning}}
+ memmove(ptr, wip, 17); // expected-warning{{source of this 'memmove' call is a pointer to ownership-qualified type}} \
+ // expected-note{{explicitly cast the pointer to silence this warning}}
+ memmove(ptr, aip, 17); // expected-warning{{source of this 'memmove' call is a pointer to ownership-qualified type}} \
+ // expected-note{{explicitly cast the pointer to silence this warning}}
+ memmove(ptr, uip, 17);
+}
diff --git a/test/SemaObjC/arc-peformselector.m b/test/SemaObjC/arc-peformselector.m
new file mode 100644
index 000000000000..e637f3d76ff4
--- /dev/null
+++ b/test/SemaObjC/arc-peformselector.m
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -verify %s
+// rdar://9659270
+
+@interface NSObject
+- (id)copy; // expected-note {{method declared here}}
+- (id) test __attribute__((ns_returns_retained)); // expected-note {{method declared here}}
++ (id) new ; // expected-note {{method declared here}}
+- (id) init __attribute__((ns_returns_not_retained));
+- (id)PlusZero;
+- (id)PlusOne __attribute__((ns_returns_retained)); // expected-note {{method declared here}}
+@end
+
+@interface I : NSObject
+{
+ SEL sel1;
+}
+- (id)performSelector:(SEL)aSelector;
+- (id)performSelector:(SEL)aSelector withObject:(id)object;
+- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
+@end
+
+@implementation I
+- (id) Meth {
+ return [self performSelector : @selector(copy)]; // expected-error {{performSelector names a selector which retains the object}}
+ return [self performSelector : @selector(test)]; // expected-error {{performSelector names a selector which retains the object}}
+ return [self performSelector : @selector(new)]; // expected-error {{performSelector names a selector which retains the object}}
+ return [self performSelector : @selector(init)];
+ return [self performSelector : sel1]; // expected-warning {{performSelector may cause a leak because its selector is unknown}} \
+ // expected-note {{used here}}
+
+ return [self performSelector : @selector(PlusZero)];
+ return [self performSelector : @selector(PlusOne)]; // expected-error {{performSelector names a selector which retains the object}}
+}
+
+- (id)performSelector:(SEL)aSelector { return 0; }
+- (id)performSelector:(SEL)aSelector withObject:(id)object { return 0; }
+- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2 { return 0; }
+@end
diff --git a/test/SemaObjC/arc-property-decl-attrs.m b/test/SemaObjC/arc-property-decl-attrs.m
new file mode 100644
index 000000000000..0dd74b8ad5ce
--- /dev/null
+++ b/test/SemaObjC/arc-property-decl-attrs.m
@@ -0,0 +1,67 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -verify %s
+// rdar://9340606
+
+@interface Foo {
+@public
+ id __unsafe_unretained x;
+ id __weak y;
+ id __autoreleasing z; // expected-error {{ivars cannot have __autoreleasing ownership}}
+}
+@property(strong) id x;
+@property(strong) id y;
+@property(strong) id z;
+@end
+
+@interface Bar {
+@public
+ id __unsafe_unretained x;
+ id __weak y;
+ id __autoreleasing z; // expected-error {{ivars cannot have __autoreleasing ownership}}
+}
+@property(retain) id x;
+@property(retain) id y;
+@property(retain) id z;
+@end
+
+@interface Bas {
+@public
+ id __unsafe_unretained x;
+ id __weak y;
+ id __autoreleasing z; // expected-error {{ivars cannot have __autoreleasing ownership}}
+}
+@property(copy) id x;
+@property(copy) id y;
+@property(copy) id z;
+@end
+
+// Errors should start about here :-)
+
+@interface Bat
+@property(strong) __unsafe_unretained id x; // expected-error {{strong property 'x' may not also be declared __unsafe_unretained}}
+@property(strong) __weak id y; // expected-error {{strong property 'y' may not also be declared __weak}} expected-error {{property attributes 'strong' and 'weak' are mutually exclusive}}
+@property(strong) __autoreleasing id z; // expected-error {{strong property 'z' may not also be declared __autoreleasing}}
+@end
+
+@interface Bau
+@property(retain) __unsafe_unretained id x; // expected-error {{strong property 'x' may not also be declared __unsafe_unretained}}
+@property(retain) __weak id y; // expected-error {{strong property 'y' may not also be declared __weak}} expected-error {{property attributes 'retain' and 'weak' are mutually exclusive}}
+@property(retain) __autoreleasing id z; // expected-error {{strong property 'z' may not also be declared __autoreleasing}}
+@end
+
+@interface Bav
+@property(copy) __unsafe_unretained id x; // expected-error {{strong property 'x' may not also be declared __unsafe_unretained}}
+@property(copy) __weak id y; // expected-error {{strong property 'y' may not also be declared __weak}} expected-error {{property attributes 'copy' and 'weak' are mutually exclusive}}
+@property(copy) __autoreleasing id z; // expected-error {{strong property 'z' may not also be declared __autoreleasing}}
+@end
+
+@interface Bingo
+@property(assign) __unsafe_unretained id x;
+@property(assign) __weak id y; // expected-error {{property attributes 'assign' and 'weak' are mutually exclusive}}
+@property(assign) __autoreleasing id z; // expected-error {{unsafe_unretained property 'z' may not also be declared __autoreleasing}}
+@end
+
+@interface Batman
+@property(unsafe_unretained) __unsafe_unretained id x;
+@property(unsafe_unretained) __weak id y; // expected-error {{property attributes 'unsafe_unretained' and 'weak' are mutually exclusive}}
+@property(unsafe_unretained) __autoreleasing id z; // expected-error {{unsafe_unretained property 'z' may not also be declared __autoreleasing}}
+@end
diff --git a/test/SemaObjC/arc-property-lifetime.m b/test/SemaObjC/arc-property-lifetime.m
new file mode 100644
index 000000000000..b1c84c75c058
--- /dev/null
+++ b/test/SemaObjC/arc-property-lifetime.m
@@ -0,0 +1,112 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -verify %s
+// rdar://9340606
+
+@interface Foo {
+@public
+ id __unsafe_unretained x;
+ id __weak y;
+ id __autoreleasing z; // expected-error {{ivars cannot have __autoreleasing ownership}}
+}
+@property(strong) id x; // expected-note {{property declared here}}
+@property(strong) id y; // expected-note {{property declared here}}
+@property(strong) id z;
+@end
+
+@implementation Foo
+@synthesize x; // expected-error {{existing ivar 'x' for strong property 'x' may not be __unsafe_unretained}}
+@synthesize y; // expected-error {{existing ivar 'y' for strong property 'y' may not be __weak}}
+@synthesize z; // suppressed
+@end
+
+@interface Bar {
+@public
+ id __unsafe_unretained x;
+ id __weak y;
+ id __autoreleasing z; // expected-error {{ivars cannot have __autoreleasing ownership}}
+}
+@property(retain) id x; // expected-note {{property declared here}}
+@property(retain) id y; // expected-note {{property declared here}}
+@property(retain) id z;
+@end
+
+@implementation Bar
+@synthesize x; // expected-error {{existing ivar 'x' for strong property 'x' may not be __unsafe_unretained}}
+@synthesize y; // expected-error {{existing ivar 'y' for strong property 'y' may not be __weak}}
+@synthesize z; // suppressed
+@end
+
+@interface Bas {
+@public
+ id __unsafe_unretained x;
+ id __weak y;
+ id __autoreleasing z; // expected-error {{ivars cannot have __autoreleasing ownership}}
+}
+@property(copy) id x; // expected-note {{property declared here}}
+@property(copy) id y; // expected-note {{property declared here}}
+@property(copy) id z;
+@end
+
+@implementation Bas
+@synthesize x; // expected-error {{existing ivar 'x' for strong property 'x' may not be __unsafe_unretained}}
+@synthesize y; // expected-error {{existing ivar 'y' for strong property 'y' may not be __weak}}
+@synthesize z; // suppressed
+@end
+
+@interface Bat
+@property(strong) __unsafe_unretained id x; // expected-error {{strong property 'x' may not also be declared __unsafe_unretained}}
+@property(strong) __autoreleasing id z; // expected-error {{strong property 'z' may not also be declared __autoreleasing}}
+@end
+
+@interface Bau
+@property(retain) __unsafe_unretained id x; // expected-error {{strong property 'x' may not also be declared __unsafe_unretained}}
+@property(retain) __autoreleasing id z; // expected-error {{strong property 'z' may not also be declared __autoreleasing}}
+@end
+
+@interface Bav
+@property(copy) __unsafe_unretained id x; // expected-error {{strong property 'x' may not also be declared __unsafe_unretained}}
+@property(copy) __autoreleasing id z; // expected-error {{strong property 'z' may not also be declared __autoreleasing}}
+@end
+
+// rdar://9341593
+@interface Gorf {
+ id __unsafe_unretained x;
+ id y;
+}
+@property(assign) id __unsafe_unretained x;
+@property(assign) id y; // expected-note {{property declared here}}
+@property(assign) id z;
+@end
+
+@implementation Gorf
+@synthesize x;
+@synthesize y; // expected-error {{existing ivar 'y' for unsafe_unretained property 'y' must be __unsafe_unretained}}
+@synthesize z;
+@end
+
+@interface Gorf2 {
+ id __unsafe_unretained x;
+ id y;
+}
+@property(unsafe_unretained) id __unsafe_unretained x;
+@property(unsafe_unretained) id y; // expected-note {{property declared here}}
+@property(unsafe_unretained) id z;
+@end
+
+@implementation Gorf2
+@synthesize x;
+@synthesize y; // expected-error {{existing ivar 'y' for unsafe_unretained property 'y' must be __unsafe_unretained}}
+@synthesize z;
+@end
+
+// rdar://9355230
+@interface I {
+ char _isAutosaving;
+}
+@property char isAutosaving;
+
+@end
+
+@implementation I
+@synthesize isAutosaving = _isAutosaving;
+@end
+
diff --git a/test/SemaObjC/arc-property.m b/test/SemaObjC/arc-property.m
new file mode 100644
index 000000000000..0651f1808dc9
--- /dev/null
+++ b/test/SemaObjC/arc-property.m
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -fblocks -verify %s
+// rdar://9309489
+
+@interface MyClass {
+ id __weak myString;
+ id StrongIvar;
+ id __weak myString2;
+ id __weak myString3;
+ id StrongIvar5;
+}
+@property (strong) id myString; // expected-note {{property declared here}}
+@property (strong) id myString1;
+@property (retain) id myString2; // expected-note {{property declared here}}
+//
+@property (weak) id myString3;
+@property (weak) id myString4;
+@property __weak id myString5; // expected-note {{property declared here}}
+@end
+
+@implementation MyClass
+@synthesize myString; // expected-error {{existing ivar 'myString' for strong property 'myString' may not be __weak}}
+@synthesize myString1 = StrongIvar; // OK
+@synthesize myString2 = myString2; // expected-error {{existing ivar 'myString2' for strong property 'myString2' may not be __weak}}
+//
+@synthesize myString3; // OK
+@synthesize myString4; // OK
+@synthesize myString5 = StrongIvar5; // expected-error {{existing ivar 'StrongIvar5' for __weak property 'myString5' must be __weak}}
+
+@end
+
+// rdar://9340692
+@interface Foo {
+@public
+ id __unsafe_unretained x; // should be __weak
+ id __strong y;
+ id __autoreleasing z; // expected-error {{ivars cannot have __autoreleasing ownership}}
+}
+@property(weak) id x; // expected-note {{property declared here}}
+@property(weak) id y; // expected-note {{property declared here}}
+@property(weak) id z;
+@end
+
+@implementation Foo
+@synthesize x; // expected-error {{existing ivar 'x' for __weak property 'x' must be __weak}}
+@synthesize y; // expected-error {{existing ivar 'y' for __weak property 'y' must be __weak}}
+@synthesize z; // suppressed
+@end
+
diff --git a/test/SemaObjC/arc-system-header.m b/test/SemaObjC/arc-system-header.m
new file mode 100644
index 000000000000..3f176577156f
--- /dev/null
+++ b/test/SemaObjC/arc-system-header.m
@@ -0,0 +1,50 @@
+// silly workaround expected-note {{marked unavailable here}}
+// RUN: %clang_cc1 -fobjc-arc -fobjc-nonfragile-abi -isystem %S/Inputs %s -DNO_USE
+// RUN: %clang_cc1 -fobjc-arc -fobjc-nonfragile-abi -isystem %S/Inputs %s -verify
+
+// another silly workaround expected-note {{marked unavailable here}}
+#include <arc-system-header.h>
+
+#ifndef NO_USE
+void test(id op, void *cp) {
+ cp = test0(op); // expected-error {{'test0' is unavailable: converts between Objective-C and C pointers in -fobjc-arc}}
+ cp = *test1(&op); // expected-error {{'test1' is unavailable: converts between Objective-C and C pointers in -fobjc-arc}}
+}
+
+// workaround expected-note {{marked unavailable here}}
+void test3(struct Test3 *p) {
+ p->field = 0; // expected-error {{'field' is unavailable: this system declaration uses an unsupported type}}
+}
+
+// workaround expected-note {{marked unavailable here}}
+void test4(Test4 *p) {
+ p->field1 = 0; // expected-error {{'field1' is unavailable: this system declaration uses an unsupported type}}
+ p->field2 = 0;
+}
+
+// workaround expected-note {{marked unavailable here}}
+void test5(struct Test5 *p) {
+ p->field = 0; // expected-error {{'field' is unavailable: this system field has retaining ownership}}
+}
+
+id test6() {
+ // This is actually okay to use if declared in a system header.
+ id x;
+ x = (id) kMagicConstant;
+ x = (id) (x ? kMagicConstant : kMagicConstant);
+ x = (id) (x ? kMagicConstant : (void*) 0);
+
+ extern void test6_helper();
+ x = (id) (test6_helper(), kMagicConstant);
+}
+
+// workaround expected-note 4 {{marked unavailable here}}
+void test7(Test7 *p) {
+ *p.prop = 0; // expected-error {{'prop' is unavailable: this system declaration uses an unsupported type}}
+ p.prop = 0; // expected-error {{'prop' is unavailable: this system declaration uses an unsupported type}}
+ *[p prop] = 0; // expected-error {{'prop' is unavailable: this system declaration uses an unsupported type}}
+ [p setProp: 0]; // expected-error {{'setProp:' is unavailable: this system declaration uses an unsupported type}}
+}
+#endif
+
+// test8 in header
diff --git a/test/SemaObjC/arc-type-conversion.m b/test/SemaObjC/arc-type-conversion.m
new file mode 100644
index 000000000000..103db5695f49
--- /dev/null
+++ b/test/SemaObjC/arc-type-conversion.m
@@ -0,0 +1,77 @@
+// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -fobjc-nonfragile-abi -fobjc-runtime-has-weak -verify -fblocks %s
+
+void * cvt(id arg)
+{
+ void* voidp_val;
+ (void)(int*)arg; // expected-error {{cast of an Objective-C pointer to 'int *' is disallowed with ARC}}
+ (void)(id)arg;
+ (void)(__autoreleasing id*)arg; // expected-error {{cast of an Objective-C pointer to '__autoreleasing id *' is disallowed with ARC}}
+ (void)(id*)arg; // expected-error {{cast of an Objective-C pointer to '__strong id *' is disallowed with ARC}}
+
+ (void)(__autoreleasing id**)voidp_val;
+ (void)(void*)voidp_val;
+ (void)(void**)arg; // expected-error {{cast of an Objective-C pointer to 'void **' is disallowed with ARC}}
+ cvt((void*)arg); // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'void *' requires a bridged cast}} \
+ // expected-error {{implicit conversion of a non-Objective-C pointer type 'void *' to 'id' is disallowed with ARC}} \
+ // expected-note{{use __bridge to convert directly (no change in ownership)}} \
+ // expected-note{{use __bridge_retained to make an ARC object available as a +1 'void *'}}
+ cvt(0);
+ (void)(__strong id**)(0);
+ return arg; // expected-error {{implicit conversion of an Objective-C pointer to 'void *' is disallowed with ARC}}
+}
+
+void to_void(__strong id *sip, __weak id *wip,
+ __autoreleasing id *aip,
+ __unsafe_unretained id *uip) {
+ void *vp1 = sip;
+ void *vp2 = wip;
+ void *vp3 = aip;
+ void *vp4 = uip;
+ (void)(void*)sip;
+ (void)(void*)wip;
+ (void)(void*)aip;
+ (void)(void*)uip;
+ (void)(void*)&sip;
+ (void)(void*)&wip;
+ (void)(void*)&aip;
+ (void)(void*)&uip;
+}
+
+void from_void(void *vp) {
+ __strong id *sip = (__strong id *)vp;
+ __weak id *wip = (__weak id *)vp;
+ __autoreleasing id *aip = (__autoreleasing id *)vp;
+ __unsafe_unretained id *uip = (__unsafe_unretained id *)vp;
+
+ __strong id **sipp = (__strong id **)vp;
+ __weak id **wipp = (__weak id **)vp;
+ __autoreleasing id **aipp = (__autoreleasing id **)vp;
+ __unsafe_unretained id **uipp = (__unsafe_unretained id **)vp;
+
+ sip = vp; // expected-error{{implicit conversion of a non-Objective-C pointer type 'void *' to '__strong id *' is disallowed with ARC}}
+ wip = vp; // expected-error{{implicit conversion of a non-Objective-C pointer type 'void *' to '__weak id *' is disallowed with ARC}}
+ aip = vp; // expected-error{{implicit conversion of a non-Objective-C pointer type 'void *' to '__autoreleasing id *' is disallowed with ARC}}
+ uip = vp; // expected-error{{implicit conversion of a non-Objective-C pointer type 'void *' to '__unsafe_unretained id *' is disallowed with ARC}}
+}
+
+typedef void (^Block)();
+typedef void (^Block_strong)() __strong;
+typedef void (^Block_autoreleasing)() __autoreleasing;
+
+@class NSString;
+
+void ownership_transfer_in_cast(void *vp, Block *pblk) {
+ __strong NSString **sip = (NSString**)(__strong id *)vp;
+ __weak NSString **wip = (NSString**)(__weak id *)vp;
+ __autoreleasing id *aip = (id*)(__autoreleasing id *)vp;
+ __unsafe_unretained id *uip = (id*)(__unsafe_unretained id *)vp;
+
+ __strong id **sipp = (id**)(__strong id **)vp;
+ __weak id **wipp = (id**)(__weak id **)vp;
+ __autoreleasing id **aipp = (id**)(__autoreleasing id **)vp;
+ __unsafe_unretained id **uipp = (id**)(__unsafe_unretained id **)vp;
+
+ Block_strong blk_strong1;
+ Block_strong blk_strong2 = (Block)blk_strong1;
+ Block_autoreleasing *blk_auto = (Block*)pblk;
+}
diff --git a/test/SemaObjC/arc-unavailable-for-weakref.m b/test/SemaObjC/arc-unavailable-for-weakref.m
new file mode 100644
index 000000000000..104314e6b1d3
--- /dev/null
+++ b/test/SemaObjC/arc-unavailable-for-weakref.m
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -verify %s
+// rdar://9693477
+
+__attribute__((objc_arc_weak_reference_unavailable))
+@interface NSOptOut1072 // expected-note {{class is declared here}}
+@end
+
+@interface sub : NSOptOut1072 @end // expected-note 2 {{class is declared here}}
+
+int main() {
+ __weak sub *w2; // expected-error {{class is incompatible with __weak references}}
+
+ __weak NSOptOut1072 *ns1; // expected-error {{class is incompatible with __weak references}}
+
+ id obj;
+
+ ns1 = (__weak sub *)obj; // expected-error {{assignment of a weak-unavailable object to a __weak object}} \
+ // expected-error {{class is incompatible with __weak references}}
+}
+
+// rdar://9732636
+__attribute__((objc_arc_weak_reference_unavailable))
+@interface NOWEAK
++ (id) new;
+@end
+
+NOWEAK * Test1() {
+ NOWEAK * strong1 = [NOWEAK new];
+ __weak id weak1;
+ weak1 = strong1; // expected-error {{assignment of a weak-unavailable object to a __weak object}}
+
+ __weak id weak2 = strong1; // expected-error {{assignment of a weak-unavailable object to a __weak object}}
+ return (__weak id)strong1; // expected-error {{cast of weak-unavailable object of type 'NOWEAK *' to a __weak object of type '__weak id'}}
+}
+
+@protocol P @end
+@protocol P1 @end
+
+NOWEAK<P, P1> * Test2() {
+ NOWEAK<P, P1> * strong1 = 0;
+ __weak id<P> weak1;
+ weak1 = strong1; // expected-error {{assignment of a weak-unavailable object to a __weak object}}
+
+ __weak id<P> weak2 = strong1; // expected-error {{assignment of a weak-unavailable object to a __weak object}}
+ return (__weak id<P>)strong1; // expected-error {{cast of weak-unavailable object of type 'NOWEAK<P,P1> *' to a __weak object of type '__weak id<P>'}}
+}
+
diff --git a/test/SemaObjC/arc-unbridged-cast.m b/test/SemaObjC/arc-unbridged-cast.m
new file mode 100644
index 000000000000..03c84cfce336
--- /dev/null
+++ b/test/SemaObjC/arc-unbridged-cast.m
@@ -0,0 +1,18 @@
+// // RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -verify %s
+// rdar://9744349
+
+typedef const struct __CFString * CFStringRef;
+
+@interface I
+@property CFStringRef P;
+@end
+
+@implementation I
+@synthesize P;
+- (id) Meth {
+ I* p1 = (id)[p1 P];
+ id p2 = (__bridge_transfer id)[p1 P];
+ id p3 = (__bridge I*)[p1 P];
+ return (id) p1.P;
+}
+@end
diff --git a/test/SemaObjC/arc-unsafe-assigns.m b/test/SemaObjC/arc-unsafe-assigns.m
new file mode 100644
index 000000000000..be8f90295e8b
--- /dev/null
+++ b/test/SemaObjC/arc-unsafe-assigns.m
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -verify %s
+// rdar://9495837
+
+@interface Foo {
+ __unsafe_unretained id unsafe_ivar;
+}
+
+@property (assign,nonatomic) id unsafe_prop;
+
+- (id)init;
++ (id)new;
++ (id)alloc;
+
+-(void)Meth;
+@end
+
+@implementation Foo
+@synthesize unsafe_prop;
+-(id)init { return self; }
++(id)new { return 0; }
++(id)alloc { return 0; }
+
+-(void)Meth {
+ self.unsafe_prop = [Foo new]; // expected-warning {{assigning retained object to unsafe property}}
+ self->unsafe_ivar = [Foo new]; // expected-warning {{assigning retained object to unsafe_unretained}}
+ self.unsafe_prop = [[Foo alloc] init]; // expected-warning {{assigning retained object to unsafe property}}
+ self->unsafe_ivar = [[Foo alloc] init]; // expected-warning {{assigning retained object to unsafe_unretained}}
+
+ __unsafe_unretained id unsafe_var;
+ unsafe_var = [Foo new]; // expected-warning {{assigning retained object to unsafe_unretained}}
+ unsafe_var = [[Foo alloc] init]; // expected-warning {{assigning retained object to unsafe_unretained}}
+}
+@end
+
+void bar(Foo *f) {
+ f.unsafe_prop = [Foo new]; // expected-warning {{assigning retained object to unsafe property}}
+
+ __unsafe_unretained id unsafe_var;
+ unsafe_var = [Foo new]; // expected-warning {{assigning retained object to unsafe_unretained}}
+ unsafe_var = [[Foo alloc] init]; // expected-warning {{assigning retained object to unsafe_unretained}}
+}
diff --git a/test/SemaObjC/arc-unsafe_unretained.m b/test/SemaObjC/arc-unsafe_unretained.m
new file mode 100644
index 000000000000..77bdded1763b
--- /dev/null
+++ b/test/SemaObjC/arc-unsafe_unretained.m
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -fblocks -fobjc-nonfragile-abi %s
+// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -fobjc-nonfragile-abi -fobjc-arc %s
+
+struct X {
+ __unsafe_unretained id object;
+ int (^ __unsafe_unretained block)(int, int);
+};
+
+void f(struct X x) {
+ x.object = 0;
+ x.block = ^(int x, int y) { return x + y; };
+}
diff --git a/test/SemaObjC/arc.m b/test/SemaObjC/arc.m
new file mode 100644
index 000000000000..3d190e5c53a0
--- /dev/null
+++ b/test/SemaObjC/arc.m
@@ -0,0 +1,628 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -fblocks -verify %s
+
+typedef unsigned long NSUInteger;
+
+void test0(void (*fn)(int), int val) {
+ fn(val);
+}
+
+@interface A
+- (id)retain;
+- (id)autorelease;
+- (oneway void)release;
+- (void)dealloc;
+- (NSUInteger)retainCount;
+@end
+
+void test1(A *a) {
+ SEL s = @selector(retain); // expected-error {{ARC forbids use of 'retain' in a @selector}}
+ s = @selector(release); // expected-error {{ARC forbids use of 'release' in a @selector}}
+ s = @selector(autorelease); // expected-error {{ARC forbids use of 'autorelease' in a @selector}}
+ s = @selector(dealloc); // expected-error {{ARC forbids use of 'dealloc' in a @selector}}
+ [a dealloc]; // expected-error {{ARC forbids explicit message send of 'dealloc'}}
+ [a retain]; // expected-error {{ARC forbids explicit message send of 'retain'}}
+ [a retainCount]; // expected-error {{ARC forbids explicit message send of 'retainCount'}}
+ [a release]; // expected-error {{ARC forbids explicit message send of 'release'}}
+ [a autorelease]; // expected-error {{ARC forbids explicit message send of 'autorelease'}}
+}
+
+@interface Test2 : A
+- (void) dealloc;
+@end
+@implementation Test2
+- (void) dealloc {
+ // This should maybe just be ignored. We're just going to warn about it for now.
+ [super dealloc]; // expected-error {{ARC forbids explicit message send of 'dealloc'}}
+}
+@end
+
+__weak __strong id x; // expected-error {{the type '__strong id' already has retainment attributes}}
+
+// rdar://8843638
+
+@interface I
+- (id)retain;
+- (id)autorelease;
+- (oneway void)release;
+- (NSUInteger)retainCount;
+@end
+
+@implementation I
+- (id)retain{return 0;} // expected-error {{ARC forbids implementation of 'retain'}}
+- (id)autorelease{return 0;} // expected-error {{ARC forbids implementation of 'autorelease'}}
+- (oneway void)release{} // expected-error {{ARC forbids implementation of 'release'}}
+- (NSUInteger)retainCount{ return 0; } // expected-error {{ARC forbids implementation of 'retainCount'}}
+@end
+
+@implementation I(CAT)
+- (id)retain{return 0;} // expected-error {{ARC forbids implementation of 'retain'}}
+- (id)autorelease{return 0;} // expected-error {{ARC forbids implementation of 'autorelease'}}
+- (oneway void)release{} // expected-error {{ARC forbids implementation of 'release'}}
+- (NSUInteger)retainCount{ return 0; } // expected-error {{ARC forbids implementation of 'retainCount'}}
+@end
+
+// rdar://8861761
+
+@interface B
+-(id)alloc;
+- (id)initWithInt: (int) i;
+@end
+
+void rdar8861761() {
+ B *o1 = [[B alloc] initWithInt:0];
+ B *o2 = [B alloc];
+ [o2 initWithInt:0]; // expected-warning {{expression result unused}}
+}
+
+// rdar://8925835
+@interface rdar8925835
+- (void)foo:(void (^)(unsigned captureCount, I * const capturedStrings[captureCount]))block;
+@end
+
+void test5() {
+ extern void test5_helper(__autoreleasing id *);
+ id x;
+
+ // Okay because of magic temporaries.
+ test5_helper(&x);
+
+ __autoreleasing id *a = &x; // expected-error {{initializing '__autoreleasing id *' with an expression of type '__strong id *' changes retain/release properties of pointer}}
+
+ a = &x; // expected-error {{assigning '__strong id *' to '__autoreleasing id *' changes retain/release properties of pointer}}
+
+ extern void test5_helper2(id const *);
+ test5_helper2(&x);
+
+ extern void test5_helper3(__weak id *); // expected-note {{passing argument to parameter here}}
+ test5_helper3(&x); // expected-error {{passing '__strong id *' to parameter of type '__weak id *' changes retain/release properties of pointer}}
+}
+
+// rdar://problem/8937869
+void test6(unsigned cond) {
+ switch (cond) {
+ case 0:
+ ;
+ id x; // expected-note {{jump bypasses initialization of retaining variable}}
+
+ case 1: // expected-error {{switch case is in protected scope}}
+ break;
+ }
+}
+
+@class NSError;
+void test7(void) {
+ extern void test7_helper(NSError **);
+ NSError *err;
+ test7_helper(&err);
+}
+void test7_weak(void) {
+ extern void test7_helper(NSError **);
+ __weak NSError *err;
+ test7_helper(&err);
+}
+void test7_unsafe(void) {
+ extern void test7_helper(NSError **); // expected-note {{passing argument to parameter here}}
+ __unsafe_unretained NSError *err;
+ test7_helper(&err); // expected-error {{passing 'NSError *__unsafe_unretained *' to parameter of type 'NSError *__autoreleasing *' changes retain/release properties of pointer}}
+}
+
+@class Test8_incomplete;
+@interface Test8_complete @end;
+@interface Test8_super @end;
+@interface Test8 : Test8_super
+- (id) init00;
+- (id) init01; // expected-note {{declaration in interface}} \
+ // expected-note{{overridden method}}
+- (id) init02; // expected-note{{overridden method}}
+- (id) init03; // covariance
+- (id) init04; // covariance
+- (id) init05; // expected-note{{overridden method}}
+
+- (void) init10; // expected-note {{declaration in interface is not in the 'init' family because its result type is not an object pointer}}
+- (void) init11;
+- (void) init12;
+- (void) init13; // expected-note {{declaration in interface is not in the 'init' family because its result type is not an object pointer}}
+- (void) init14; // expected-note {{declaration in interface is not in the 'init' family because its result type is not an object pointer}}
+- (void) init15;
+
+// These should be invalid to actually call.
+- (Test8_incomplete*) init20;
+- (Test8_incomplete*) init21; // expected-note {{declaration in interface}}
+- (Test8_incomplete*) init22;
+- (Test8_incomplete*) init23;
+- (Test8_incomplete*) init24;
+- (Test8_incomplete*) init25;
+
+- (Test8_super*) init30; // id exception to covariance
+- (Test8_super*) init31; // expected-note {{declaration in interface}} \
+ // expected-note{{overridden method}}
+- (Test8_super*) init32; // expected-note{{overridden method}}
+- (Test8_super*) init33;
+- (Test8_super*) init34; // covariance
+- (Test8_super*) init35; // expected-note{{overridden method}}
+
+- (Test8*) init40; // id exception to covariance
+- (Test8*) init41; // expected-note {{declaration in interface}} \
+ // expected-note{{overridden method}}
+- (Test8*) init42; // expected-note{{overridden method}}
+- (Test8*) init43; // this should be a warning, but that's a general language thing, not an ARC thing
+- (Test8*) init44;
+- (Test8*) init45; // expected-note{{overridden method}}
+
+- (Test8_complete*) init50; // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_complete*) init51; // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_complete*) init52; // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_complete*) init53; // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_complete*) init54; // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_complete*) init55; // expected-error {{init methods must return a type related to the receiver type}}
+@end
+@implementation Test8
+- (id) init00 { return 0; }
+- (id) init10 { return 0; } // expected-error {{method implementation does not match its declaration}}
+- (id) init20 { return 0; }
+- (id) init30 { return 0; }
+- (id) init40 { return 0; }
+- (id) init50 { return 0; }
+
+- (void) init01 {} // expected-error {{method was declared as an 'init' method, but its implementation doesn't match because its result type is not an object pointer}} \
+ // expected-warning{{ method is expected to return an instance of its class type 'Test8', but is declared to return 'void'}}
+- (void) init11 {}
+- (void) init21 {} // expected-error {{method was declared as an 'init' method, but its implementation doesn't match because its result type is not an object pointer}}
+- (void) init31 {} // expected-error {{method was declared as an 'init' method, but its implementation doesn't match because its result type is not an object pointer}} \
+ // expected-warning{{ method is expected to return an instance of its class type 'Test8', but is declared to return 'void'}}
+- (void) init41 {} // expected-error {{method was declared as an 'init' method, but its implementation doesn't match because its result type is not an object pointer}} \
+ // expected-warning{{ method is expected to return an instance of its class type 'Test8', but is declared to return 'void'}}
+- (void) init51 {}
+
+- (Test8_incomplete*) init02 { return 0; } // expected-error {{init methods must return a type related to the receiver type}} \
+ // expected-warning{{method is expected to return an instance of its class type 'Test8', but is declared to return 'Test8_incomplete *'}}
+- (Test8_incomplete*) init12 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_incomplete*) init22 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_incomplete*) init32 { return 0; } // expected-error {{init methods must return a type related to the receiver type}} \
+ // expected-warning{{method is expected to return an instance of its class type 'Test8', but is declared to return 'Test8_incomplete *'}}
+- (Test8_incomplete*) init42 { return 0; } // expected-error {{init methods must return a type related to the receiver type}} \
+ // expected-warning{{method is expected to return an instance of its class type 'Test8', but is declared to return 'Test8_incomplete *'}}
+- (Test8_incomplete*) init52 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
+
+- (Test8_super*) init03 { return 0; }
+- (Test8_super*) init13 { return 0; } // expected-error {{method implementation does not match its declaration}}
+- (Test8_super*) init23 { return 0; }
+- (Test8_super*) init33 { return 0; }
+- (Test8_super*) init43 { return 0; }
+- (Test8_super*) init53 { return 0; }
+
+- (Test8*) init04 { return 0; }
+- (Test8*) init14 { return 0; } // expected-error {{method implementation does not match its declaration}}
+- (Test8*) init24 { return 0; }
+- (Test8*) init34 { return 0; }
+- (Test8*) init44 { return 0; }
+- (Test8*) init54 { return 0; }
+
+- (Test8_complete*) init05 { return 0; } // expected-error {{init methods must return a type related to the receiver type}} \
+ // expected-warning{{method is expected to return an instance of its class type 'Test8', but is declared to return 'Test8_complete *'}}
+- (Test8_complete*) init15 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_complete*) init25 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_complete*) init35 { return 0; } // expected-error {{init methods must return a type related to the receiver type}} \
+ // expected-warning{{method is expected to return an instance of its class type 'Test8', but is declared to return 'Test8_complete *'}}
+- (Test8_complete*) init45 { return 0; } // expected-error {{init methods must return a type related to the receiver type}} \
+ // expected-warning{{method is expected to return an instance of its class type 'Test8', but is declared to return 'Test8_complete *'}}
+- (Test8_complete*) init55 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
+@end
+
+@class Test9_incomplete;
+@interface Test9
+- (Test9_incomplete*) init1; // expected-error {{init methods must return a type related to the receiver type}}
+- (Test9_incomplete*) init2;
+@end
+id test9(Test9 *v) {
+ return [v init1];
+}
+
+// Test that the inference rules are different for fast enumeration variables.
+void test10(id collection) {
+ for (id x in collection) {
+ __strong id *ptr = &x; // expected-warning {{initializing '__strong id *' with an expression of type 'const __strong id *' discards qualifiers}}
+ }
+
+ for (__strong id x in collection) {
+ __weak id *ptr = &x; // expected-error {{initializing '__weak id *' with an expression of type '__strong id *' changes retain/release properties of pointer}}
+ }
+}
+
+// rdar://problem/9078626
+#define nil ((void*) 0)
+void test11(id op, void *vp) {
+ _Bool b;
+ b = (op == nil);
+ b = (nil == op);
+
+ b = (vp == nil);
+ b = (nil == vp);
+
+ b = (vp == op); // expected-error {{implicit conversion of an Objective-C pointer to 'void *'}}
+ b = (op == vp); // expected-error {{implicit conversion of a non-Objective-C pointer type 'void *' to 'id'}}
+}
+
+void test12(id collection) {
+ for (id x in collection) {
+ x = 0; // expected-error {{fast enumeration variables can't be modified in ARC by default; declare the variable __strong to allow this}}
+ }
+
+ for (const id x in collection) {
+ x = 0; // expected-error {{read-only variable is not assignable}}
+ }
+
+ for (__strong id x in collection) {
+ x = 0;
+ }
+}
+
+@interface Test13
+- (id) init0;
+- (void) noninit;
+@end
+@implementation Test13
+- (id) init0 {
+ self = 0;
+}
+- (void) noninit {
+ self = 0; // expected-error {{cannot assign to 'self' outside of a method in the init family}}
+}
+@end
+
+// rdar://problem/9172151
+@class Test14A, Test14B;
+void test14() {
+ extern void test14_consume(id *);
+ extern int test14_cond(void);
+ extern float test14_nowriteback(id __autoreleasing const *); // expected-note{{passing argument to parameter here}}
+
+ Test14A *a;
+ Test14B *b;
+ id i;
+ id cla[10];
+ id vla[test14_cond() + 10];
+
+ test14_consume((__strong id*) &a);
+ test14_consume((test14_cond() ? (__strong id*) &b : &i));
+ test14_consume(test14_cond() ? 0 : &a);
+ test14_consume(test14_cond() ? (void*) 0 : (&a));
+ test14_consume(cla); // expected-error {{passing address of non-scalar object to __autoreleasing parameter for write-back}}
+ test14_consume(vla); // expected-error {{passing address of non-scalar object to __autoreleasing parameter for write-back}}
+ test14_consume(&cla[5]); // expected-error {{passing address of non-scalar object to __autoreleasing parameter for write-back}}
+
+ __strong id *test14_indirect(void);
+ test14_consume(test14_indirect()); // expected-error {{passing address of non-local object to __autoreleasing parameter for write-back}}
+
+ extern id test14_global;
+ test14_consume(&test14_global); // expected-error {{passing address of non-local object to __autoreleasing parameter for write-back}}
+
+ extern __strong id *test14_global_ptr;
+ test14_consume(test14_global_ptr); // expected-error {{passing address of non-local object to __autoreleasing parameter for write-back}}
+
+ static id static_local;
+ test14_consume(&static_local); // expected-error {{passing address of non-local object to __autoreleasing parameter for write-back}}
+
+ __weak id* wip;
+ test14_nowriteback(&static_local); // okay, not a write-back.
+ test14_nowriteback(wip); // expected-error{{passing '__weak id *' to parameter of type '__autoreleasing id const *' changes retain/release properties of pointer}}
+}
+
+void test15() {
+ __block __autoreleasing id x; // expected-error {{__block variables cannot have __autoreleasing ownership}}
+}
+
+struct Test16;
+@interface Test16a
+- (void) test16_0: (int) x;
+- (int) test16_1: (int) x; // expected-note {{one possibility}}
+- (int) test16_2: (int) x; // expected-note {{one possibility}}
+- (id) test16_3: (int) x __attribute__((ns_returns_retained)); // expected-note {{one possibility}}
+- (void) test16_4: (int) x __attribute__((ns_consumes_self)); // expected-note {{one possibility}}
+- (void) test16_5: (id) __attribute__((ns_consumed)) x; // expected-note {{one possibility}}
+- (void) test16_6: (id) x;
+@end
+
+@interface Test16b
+- (void) test16_0: (int) x;
+- (int) test16_1: (char*) x; // expected-note {{also found}}
+- (char*) test16_2: (int) x; // expected-note {{also found}}
+- (id) test16_3: (int) x; // expected-note {{also found}}
+- (void) test16_4: (int) x; // expected-note {{also found}}
+- (void) test16_5: (id) x; // expected-note {{also found}}
+- (void) test16_6: (struct Test16 *) x;
+@end
+
+void test16(void) {
+ id v;
+ [v test16_0: 0];
+ [v test16_1: 0]; // expected-error {{multiple methods named 'test16_1:' found with mismatched result, parameter type or attributes}}
+ [v test16_2: 0]; // expected-error {{multiple methods named}}
+ [v test16_3: 0]; // expected-error {{multiple methods named}}
+ [v test16_4: 0]; // expected-error {{multiple methods named}}
+ [v test16_5: 0]; // expected-error {{multiple methods named}}
+ [v test16_6: 0];
+}
+
+@class Test17;
+@protocol Test17p
+- (void) test17;
++ (void) test17;
+@end
+void test17(void) {
+ Test17 *v0;
+ [v0 test17]; // expected-error {{receiver type 'Test17' for instance message is a forward declaration}}
+
+ Test17<Test17p> *v1;
+ [v1 test17]; // expected-error {{receiver type 'Test17<Test17p>' for instance message is a forward declaration}}
+
+ [Test17 test17]; // expected-error {{receiver 'Test17' for class message is a forward declaration}}
+}
+
+void test18(void) {
+ id x;
+ [x test18]; // expected-error {{no known instance method for selector 'test18'}}
+}
+
+extern struct Test19 *test19a;
+struct Test19 *const test19b = 0;
+void test19(void) {
+ id x;
+ x = (id) test19a; // expected-error {{bridged cast}} \
+ // expected-note{{use __bridge to convert directly (no change in ownership))}} \
+ // expected-note{{use __bridge_transfer to transfer ownership of a +1 'struct Test19 *' into ARC}}
+ x = (id) test19b; // expected-error {{bridged cast}} \
+ // expected-note{{use __bridge to convert directly (no change in ownership)}} \
+ // expected-note{{use __bridge_transfer to transfer ownership of a +1 'struct Test19 *' into ARC}}
+}
+
+// rdar://problem/8951453
+static __thread id test20_implicit; // expected-error {{thread-local variable has non-trivial ownership: type is '__strong id'}}
+static __thread __strong id test20_strong; // expected-error {{thread-local variable has non-trivial ownership: type is '__strong id'}}
+static __thread __weak id test20_weak; // expected-error {{thread-local variable has non-trivial ownership: type is '__weak id'}}
+static __thread __autoreleasing id test20_autoreleasing; // expected-error {{thread-local variable has non-trivial ownership: type is '__autoreleasing id'}} expected-error {{global variables cannot have __autoreleasing ownership}}
+static __thread __unsafe_unretained id test20_unsafe;
+void test20(void) {
+ static __thread id test20_implicit; // expected-error {{thread-local variable has non-trivial ownership: type is '__strong id'}}
+ static __thread __strong id test20_strong; // expected-error {{thread-local variable has non-trivial ownership: type is '__strong id'}}
+ static __thread __weak id test20_weak; // expected-error {{thread-local variable has non-trivial ownership: type is '__weak id'}}
+ static __thread __autoreleasing id test20_autoreleasing; // expected-error {{thread-local variable has non-trivial ownership: type is '__autoreleasing id'}} expected-error {{global variables cannot have __autoreleasing ownership}}
+ static __thread __unsafe_unretained id test20_unsafe;
+}
+
+// rdar://9310049
+_Bool fn(id obj) {
+ return (_Bool)obj;
+}
+
+// Check casting w/ ownership qualifiers.
+void test21() {
+ __strong id *sip;
+ (void)(__weak id *)sip; // expected-error{{casting '__strong id *' to type '__weak id *' changes retain/release properties of pointer}}
+ (void)(__weak const id *)sip; // expected-error{{casting '__strong id *' to type '__weak id const *' changes retain/release properties of pointer}}
+ (void)(__autoreleasing id *)sip; // expected-error{{casting '__strong id *' to type '__autoreleasing id *' changes retain/release properties of pointer}}
+ (void)(__autoreleasing const id *)sip; // okay
+}
+
+// rdar://problem/9340462
+void test22(id x[]) { // expected-error {{must explicitly describe intended ownership of an object array parameter}}
+}
+
+// rdar://problem/9400219
+void test23(void) {
+ void *ptr;
+ ptr = @"foo";
+ ptr = (ptr ? @"foo" : 0);
+ ptr = (ptr ? @"foo" : @"bar");
+}
+
+id test24(void) {
+ extern void test24_helper(void);
+ return test24_helper(), (void*) 0;
+}
+
+// rdar://9400841
+@interface Base
+@property (assign) id content;
+@end
+
+@interface Foo : Base
+-(void)test;
+@end
+
+@implementation Foo
+-(void)test {
+ super.content = 0;
+}
+@end
+
+// <rdar://problem/9398437>
+void test25(Class *classes) {
+ Class *other_classes;
+ test25(other_classes);
+}
+
+void test26(id y) {
+ extern id test26_var1;
+ __sync_swap(&test26_var1, 0, y); // expected-error {{cannot perform atomic operation on a pointer to type '__strong id': type has non-trivial ownership}}
+
+ extern __unsafe_unretained id test26_var2;
+ __sync_swap(&test26_var2, 0, y);
+}
+
+@interface Test26
+- (id) init;
+- (id) initWithInt: (int) x;
+@end
+@implementation Test26
+- (id) init { return self; }
+- (id) initWithInt: (int) x {
+ [self init]; // expected-error {{the result of a delegate init call must be immediately returned or assigned to 'self'}}
+ return self;
+}
+@end
+
+// rdar://9525555
+@interface Test27
+@property id x; // expected-warning {{no 'assign', 'retain', or 'copy' attribute is specified - 'assign' is assumed}} \
+ // expected-warning {{default property attribute 'assign' not appropriate for non-gc object}} \
+ // expected-note {{declared here}}
+@property (readonly) id ro; // expected-note {{declared here}}
+@property (readonly) id custom_ro;
+@property int y;
+@end
+
+@implementation Test27
+@synthesize x; // expected-error {{ARC forbids synthesizing a property of an Objective-C object with unspecified storage attribute}}
+@synthesize ro; // expected-error {{ARC forbids synthesizing a property of an Objective-C object with unspecified storage attribute}}
+@synthesize y;
+-(id)custom_ro { return 0; }
+@end
+
+// rdar://9569264
+@interface Test28
+@property (nonatomic, assign) __strong id a; // expected-error {{unsafe_unretained property 'a' may not also be declared __strong}}
+@end
+
+@interface Test28 ()
+@property (nonatomic, assign) __strong id b; // expected-error {{unsafe_unretained property 'b' may not also be declared __strong}}
+@end
+
+@implementation Test28
+@synthesize a;
+@synthesize b;
+@end
+
+// rdar://9573962
+typedef struct Bark Bark;
+@interface Test29
+@property Bark* P;
+@end
+
+@implementation Test29
+@synthesize P;
+- (id)Meth {
+ Bark** f = &P;
+ return 0;
+}
+@end
+
+// rdar://9495837
+@interface Test30
++ (id) new;
+- (void)Meth;
+@end
+
+@implementation Test30
++ (id) new { return 0; }
+- (void) Meth {
+ __weak id x = [Test30 new]; // expected-warning {{assigning retained object to weak variable}}
+ id __unsafe_unretained u = [Test30 new]; // expected-warning {{assigning retained object to unsafe_unretained variable}}
+ id y = [Test30 new];
+ x = [Test30 new]; // expected-warning {{assigning retained object to weak variable}}
+ u = [Test30 new]; // expected-warning {{assigning retained object to unsafe_unretained variable}}
+ y = [Test30 new];
+}
+@end
+
+// rdar://9411838
+@protocol PTest31 @end
+
+int Test31() {
+ Class cls;
+ id ids;
+ id<PTest31> pids;
+ Class<PTest31> pcls;
+
+ int i = (ids->isa ? 1 : 0); // expected-error {{member reference base type 'id' is not a structure or union}}
+ int j = (pids->isa ? 1 : 0); // expected-error {{member reference base type 'id<PTest31>' is not a structure or union}}
+ int k = (pcls->isa ? i : j); // expected-error {{member reference base type 'Class<PTest31>' is not a structure or union}}
+ return cls->isa ? i : j; // expected-error {{member reference base type 'Class' is not a structure or union}}
+}
+
+// rdar://9612030
+@interface ITest32 {
+@public
+ id ivar;
+}
+@end
+
+id Test32(__weak ITest32 *x) {
+ __weak ITest32 *y;
+ x->ivar = 0; // expected-error {{dereferencing a __weak pointer is not allowed}}
+ return y ? y->ivar // expected-error {{dereferencing a __weak pointer is not allowed}}
+ : (*x).ivar; // expected-error {{dereferencing a __weak pointer is not allowed}}
+}
+
+// rdar://9619861
+extern int printf(const char*, ...);
+typedef long intptr_t;
+
+int Test33(id someid) {
+ printf( "Hello%ld", (intptr_t)someid);
+ return (int)someid;
+}
+
+// rdar://9636091
+@interface I34
+@property (nonatomic, retain) id newName __attribute__((ns_returns_not_retained)) ;
+
+@property (nonatomic, retain) id newName1 __attribute__((ns_returns_not_retained)) ;
+- (id) newName1 __attribute__((ns_returns_not_retained));
+
+@property (nonatomic, retain) id newName2 __attribute__((ns_returns_not_retained)); // expected-note {{roperty declared here}}
+- (id) newName2; // expected-warning {{property declared as returning non-retained objects; getter returning retained objects}}
+@end
+
+@implementation I34
+@synthesize newName;
+
+@synthesize newName1;
+- (id) newName1 { return 0; }
+
+@synthesize newName2;
+@end
+
+void test35(void) {
+ extern void test36_helper(id*);
+ id x;
+ __strong id *xp = 0;
+
+ test36_helper(&x);
+ test36_helper(xp); // expected-error {{passing address of non-local object to __autoreleasing parameter for write-back}}
+
+ // rdar://problem/9665710
+ __block id y;
+ test36_helper(&y);
+ ^{ test36_helper(&y); }();
+
+ __strong int non_objc_type; // expected-warning {{'__strong' only applies to objective-c object or block pointer types}}
+}
+
+void test36(int first, ...) {
+ // <rdar://problem/9758798>
+ __builtin_va_list arglist;
+ __builtin_va_start(arglist, first);
+ id obj = __builtin_va_arg(arglist, id);
+ __builtin_va_end(arglist);
+}
diff --git a/test/SemaObjC/autoreleasepool.m b/test/SemaObjC/autoreleasepool.m
new file mode 100644
index 000000000000..41e17681afdf
--- /dev/null
+++ b/test/SemaObjC/autoreleasepool.m
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+void *objc_autoreleasepool_push();
+void autoreleasepool_pop(void*);
+
+@interface AUTORP @end
+
+@implementation AUTORP
+- (void) unregisterTask:(id) task {
+ goto L; // expected-error {{goto into protected scope}}
+
+ @autoreleasepool { // expected-note {{jump bypasses auto release push of @autoreleasepool block}}
+ void *tmp = objc_autoreleasepool_push();
+ L:
+ autoreleasepool_pop(tmp);
+ @autoreleasepool {
+ return;
+ }
+ }
+}
+@end
+
diff --git a/test/SemaObjC/class-proto-1.m b/test/SemaObjC/class-proto-1.m
index 246b5002f67f..80309764335b 100644
--- a/test/SemaObjC/class-proto-1.m
+++ b/test/SemaObjC/class-proto-1.m
@@ -23,9 +23,9 @@
@interface E2 <p1,p2,p3> @end // expected-warning {{cannot find protocol definition for 'p3'}}
-@class U1, U2;
+@class U1, U2; // expected-note {{forward class is declared here}}
-@interface E3 : U1 @end // expected-error {{cannot find interface declaration for 'U1', superclass of 'E3'}}
+@interface E3 : U1 @end // expected-error {{attempting to use the forward class 'U1' as superclass of 'E3'}}
@interface I3 : E3 @end
diff --git a/test/SemaObjC/class-unavail-warning.m b/test/SemaObjC/class-unavail-warning.m
index 426ac772c8aa..408647ac11c1 100644
--- a/test/SemaObjC/class-unavail-warning.m
+++ b/test/SemaObjC/class-unavail-warning.m
@@ -2,7 +2,7 @@
// rdar://9092208
__attribute__((unavailable("not available")))
-@interface MyClass { // expected-note 5 {{function has been explicitly marked unavailable here}}
+@interface MyClass { // expected-note 5 {{declaration has been explicitly marked unavailable here}}
@public
void *_test;
}
diff --git a/test/SemaObjC/debugger-support.m b/test/SemaObjC/debugger-support.m
new file mode 100644
index 000000000000..21c096edad43
--- /dev/null
+++ b/test/SemaObjC/debugger-support.m
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fdebugger-support %s -emit-llvm -o - | FileCheck %s
+
+// rdar://problem/9416370
+void test0(id x) {
+ struct A { int w, x, y, z; };
+ struct A result = (struct A) [x makeStruct];
+ // CHECK: define void @test0(
+ // CHECK: [[X:%.*]] = alloca i8*, align 8
+ // CHECK-NEXT: [[RESULT:%.*]] = alloca [[A:%.*]], align 4
+ // CHECK-NEXT: store i8* {{%.*}}, i8** [[X]],
+ // CHECK-NEXT: [[T0:%.*]] = load i8** [[X]],
+ // CHECK-NEXT: [[T1:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_"
+ // CHECK-NEXT: [[T2:%.*]] = call { i64, i64 } bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to { i64, i64 } (i8*, i8*)*)(i8* [[T0]], i8* [[T1]])
+}
diff --git a/test/SemaObjC/error-property-gc-attr.m b/test/SemaObjC/error-property-gc-attr.m
index a77b68bff0ea..829c08228747 100644
--- a/test/SemaObjC/error-property-gc-attr.m
+++ b/test/SemaObjC/error-property-gc-attr.m
@@ -20,9 +20,9 @@
@implementation INTF
@synthesize pweak=IVAR; // expected-error {{existing ivar 'IVAR' for __weak property 'pweak' must be __weak}}
-@synthesize NOT=II; // expected-error {{property 'NOT' must be declared __weak to match existing ivar 'II' with __weak attribute}}
+@synthesize NOT=II; // expected-error {{existing ivar 'II' for strong property 'NOT' may not be __weak}}
@synthesize WID;
@synthesize ID;
-@synthesize AWEAK; // expected-error {{property 'AWEAK' must be declared __weak to match existing ivar 'AWEAK' with __weak attribute}}
+@synthesize AWEAK; // expected-error {{existing ivar 'AWEAK' for strong property 'AWEAK' may not be __weak}}
@synthesize WI;
@end
diff --git a/test/SemaObjC/forward-class-1.m b/test/SemaObjC/forward-class-1.m
index ab213fb4ce72..de94e884aee2 100644
--- a/test/SemaObjC/forward-class-1.m
+++ b/test/SemaObjC/forward-class-1.m
@@ -1,9 +1,9 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-@class FOO, BAR;
+@class FOO, BAR; // expected-note {{forward class is declared here}}
@class FOO, BAR;
-@interface INTF : FOO // expected-error {{cannot find interface declaration for 'FOO', superclass of 'INTF'}}
+@interface INTF : FOO // expected-error {{attempting to use the forward class 'FOO' as superclass of 'INTF'}}
@end
@interface FOO
@@ -45,3 +45,14 @@ typedef NSObject <XCElementP> XCElement;
@end
+// rdar://9653341
+@class B; // expected-note {{forward class is declared here}}
+@interface A : B {} // expected-error {{attempting to use the forward class 'B' as superclass of 'A'}}
+@end
+
+@interface B : A {}
+@end
+
+@implementation A @end
+@implementation B @end
+
diff --git a/test/SemaObjC/ivar-ref-misuse.m b/test/SemaObjC/ivar-ref-misuse.m
index ba2f11594f96..f6d9c9408445 100644
--- a/test/SemaObjC/ivar-ref-misuse.m
+++ b/test/SemaObjC/ivar-ref-misuse.m
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-@interface Sprite {
+@interface Sprite { // expected-note{{'Sprite' declared here}}
int sprite, spree;
int UseGlobalBar;
}
@@ -17,7 +17,8 @@ int UseGlobalBar;
+ (void)setFoo:(int)foo {
sprite = foo; // expected-error {{instance variable 'sprite' accessed in class method}}
spree = foo;
- Xsprite = foo; // expected-error {{use of undeclared identifier 'Xsprite'}}
+ Xsprite = foo; // expected-error {{unknown type name 'Xsprite'; did you mean 'Sprite'?}} \
+ // expected-error{{expected identifier or '('}}
UseGlobalBar = 10;
}
+ (void)setSprite:(int)sprite {
diff --git a/test/SemaObjC/method-lookup-3.m b/test/SemaObjC/method-lookup-3.m
index 882b3d1d2123..b3d9c46484c3 100644
--- a/test/SemaObjC/method-lookup-3.m
+++ b/test/SemaObjC/method-lookup-3.m
@@ -55,3 +55,19 @@ void f5(id a0, Abstract *a1) {
void f6(id<A> a0) {
Abstract *l = [a0 x];
}
+
+struct test3a { int x, y; };
+struct test3b { unsigned x, y; };
+@interface Test3A - (struct test3a) test3; @end
+@interface Test3B - (struct test3b) test3; @end
+void test3(id x) {
+ (void) [x test3];
+}
+
+struct test4a { int x, y; };
+struct test4b { float x, y; };
+@interface Test4A - (struct test4a) test4; @end //expected-note{{using}}
+@interface Test4B - (struct test4b) test4; @end //expected-note{{also found}}
+void test4(id x) {
+ (void) [x test4]; //expected-warning {{multiple methods named 'test4' found}}
+}
diff --git a/test/SemaObjC/no-warning-unavail-unimp.m b/test/SemaObjC/no-warning-unavail-unimp.m
new file mode 100644
index 000000000000..94093222e8c9
--- /dev/null
+++ b/test/SemaObjC/no-warning-unavail-unimp.m
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// rdar://9651605
+
+@interface Foo
+@property (getter=getVal) int val __attribute__((unavailable));
+- Method __attribute__((unavailable));
++ CMethod __attribute__((unavailable));
+@end
+
+@implementation Foo
+@end
+
diff --git a/test/SemaObjC/property-10.m b/test/SemaObjC/property-10.m
index 011927368fa3..e89d68e9d051 100644
--- a/test/SemaObjC/property-10.m
+++ b/test/SemaObjC/property-10.m
@@ -5,14 +5,24 @@
@interface I0
@property(readonly, readwrite) int p0; // expected-error {{property attributes 'readonly' and 'readwrite' are mutually exclusive}}
-@property(retain) int p1; // expected-error {{property with 'retain' attribute must be of object type}}
+@property(retain) int p1; // expected-error {{property with 'retain (or strong)' attribute must be of object type}}
+@property(strong) int s1; // expected-error {{property with 'retain (or strong)' attribute must be of object type}}
@property(copy) int p2; // expected-error {{property with 'copy' attribute must be of object type}}
@property(assign, copy) id p3_0; // expected-error {{property attributes 'assign' and 'copy' are mutually exclusive}}
@property(assign, retain) id p3_1; // expected-error {{property attributes 'assign' and 'retain' are mutually exclusive}}
+@property(assign, strong) id s3_1; // expected-error {{property attributes 'assign' and 'strong' are mutually exclusive}}
@property(copy, retain) id p3_2; // expected-error {{property attributes 'copy' and 'retain' are mutually exclusive}}
+@property(copy, strong) id s3_2; // expected-error {{property attributes 'copy' and 'strong' are mutually exclusive}}
@property(assign, copy, retain) id p3_3; // expected-error {{property attributes 'assign' and 'copy' are mutually exclusive}}, expected-error {{property attributes 'assign' and 'retain' are mutually exclusive}}
+@property(assign, copy, strong) id s3_3; // expected-error {{property attributes 'assign' and 'copy' are mutually exclusive}}, expected-error {{property attributes 'assign' and 'strong' are mutually exclusive}}
+
+@property(unsafe_unretained, copy) id p4_0; // expected-error {{property attributes 'unsafe_unretained' and 'copy' are mutually exclusive}}
+@property(unsafe_unretained, retain) id p4_1; // expected-error {{property attributes 'unsafe_unretained' and 'retain' are mutually exclusive}}
+@property(unsafe_unretained, strong) id s4_1; // expected-error {{property attributes 'unsafe_unretained' and 'strong' are mutually exclusive}}
+@property(unsafe_unretained, copy, retain) id p4_3; // expected-error {{property attributes 'unsafe_unretained' and 'copy' are mutually exclusive}}, expected-error {{property attributes 'unsafe_unretained' and 'retain' are mutually exclusive}}
+@property(unsafe_unretained, copy, strong) id s4_3; // expected-error {{property attributes 'unsafe_unretained' and 'copy' are mutually exclusive}}, expected-error {{property attributes 'unsafe_unretained' and 'strong' are mutually exclusive}}
@property id p4; // expected-warning {{no 'assign', 'retain', or 'copy' attribute is specified - 'assign' is assumed}}, expected-warning {{default property attribute 'assign' not appropriate for non-gc object}}
@@ -22,7 +32,8 @@
@end
@interface I0()
-@property (retain) int PROP; // expected-error {{property with 'retain' attribute must be of object type}}
+@property (retain) int PROP; // expected-error {{property with 'retain (or strong)' attribute must be of object type}}
+@property (strong) int SPROP; // expected-error {{property with 'retain (or strong)' attribute must be of object type}}
@property(nonatomic,copy) int (*PROP1)(); // expected-error {{property with 'copy' attribute must be of object type}}
+@property(nonatomic,weak) int (*PROP2)(); // expected-error {{property with 'weak' attribute must be of object type}}
@end
-
diff --git a/test/SemaObjC/property-inherited.m b/test/SemaObjC/property-inherited.m
index 5c5631e6fb89..11ef2befa99b 100644
--- a/test/SemaObjC/property-inherited.m
+++ b/test/SemaObjC/property-inherited.m
@@ -1,6 +1,8 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify
+// RUN: %clang_cc1 -x objective-c++ %s -fsyntax-only -verify
-// <rdar://problem/6497242> Inherited overridden protocol declared objects don't work
+// rdar://6497242 Inherited overridden protocol declared objects don't work
+// rdar://9740328 Case for c++
@protocol NSObject @end
@interface NSObject @end
diff --git a/test/SemaObjC/property-ns-returns-not-retained-attr.m b/test/SemaObjC/property-ns-returns-not-retained-attr.m
new file mode 100644
index 000000000000..187c93f3d3af
--- /dev/null
+++ b/test/SemaObjC/property-ns-returns-not-retained-attr.m
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fsyntax-only -verify %s
+// rdar://9636091
+
+@interface I
+@property (nonatomic, retain) id newName __attribute__((ns_returns_not_retained)) ;
+
+@property (nonatomic, retain) id newName1 __attribute__((ns_returns_not_retained)) ;
+- (id) newName1 __attribute__((ns_returns_not_retained));
+
+@property (nonatomic, retain) id newName2 __attribute__((ns_returns_not_retained)); // expected-note {{roperty declared here}}
+- (id) newName2; // expected-warning {{property declared as returning non-retained objects; getter returning retained objects}}
+@end
+
+@implementation I
+@synthesize newName;
+
+@synthesize newName1;
+- (id) newName1 { return 0; }
+
+@synthesize newName2;
+@end
diff --git a/test/SemaObjC/related-result-type-inference.m b/test/SemaObjC/related-result-type-inference.m
index f5399180c400..094f19a67129 100644
--- a/test/SemaObjC/related-result-type-inference.m
+++ b/test/SemaObjC/related-result-type-inference.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-infer-related-result-type -verify %s
+// RUN: %clang_cc1 -verify %s
@interface Unrelated
@end
diff --git a/test/SemaObjC/selector-3.m b/test/SemaObjC/selector-3.m
index 69a74f830ce5..b248a5d036ab 100644
--- a/test/SemaObjC/selector-3.m
+++ b/test/SemaObjC/selector-3.m
@@ -27,3 +27,28 @@ SEL func()
{
return @selector(length); // expected-warning {{unimplemented selector 'length'}}
}
+
+// rdar://9545564
+@class MSPauseManager;
+
+@protocol MSPauseManagerDelegate
+@optional
+- (void)pauseManagerDidPause:(MSPauseManager *)manager;
+- (int)respondsToSelector:(SEL)aSelector;
+@end
+
+@interface MSPauseManager
+{
+ id<MSPauseManagerDelegate> _delegate;
+}
+@end
+
+
+@implementation MSPauseManager
+- (id) Meth {
+ if ([_delegate respondsToSelector:@selector(pauseManagerDidPause:)])
+ return 0;
+ return 0;
+}
+@end
+
diff --git a/test/SemaObjC/self-declared-in-block.m b/test/SemaObjC/self-declared-in-block.m
index 4bd720214438..21310953c2c5 100644
--- a/test/SemaObjC/self-declared-in-block.m
+++ b/test/SemaObjC/self-declared-in-block.m
@@ -7,11 +7,12 @@
@implementation Blocky {
int _a;
}
-- (void)doAThing {
+- (int)doAThing {
^{
- char self; // expected-note {{declared here}}
- _a; // expected-error {{instance variable '_a' cannot be accessed because 'self' has been redeclared}}
+ char self;
+ return _a;
}();
+ return _a;
}
@end
@@ -37,14 +38,14 @@
(void)_anIvar;
}
{
- C* self; // expected-note {{declared here}}
- (void) _anIvar; // expected-error {{instance variable '_anIvar' cannot be accessed because 'self' has been redeclared}}
+ C* self;
+ (void) _anIvar;
}
}
- (void)doAThing {
^{
- id self; // expected-note {{declared here}}
- (void)_anIvar; // expected-error {{instance variable '_anIvar' cannot be accessed because 'self' has been redeclared}}
+ id self;
+ (void)_anIvar;
}();
}
@end
diff --git a/test/SemaObjC/sizeof-interface.m b/test/SemaObjC/sizeof-interface.m
index 3fe39645fddb..65c8e49e0b87 100644
--- a/test/SemaObjC/sizeof-interface.m
+++ b/test/SemaObjC/sizeof-interface.m
@@ -7,7 +7,7 @@ int g0 = sizeof(I0); // expected-error{{invalid application of 'sizeof' to an in
// rdar://6821047
void *g3(I0 *P) {
- P = P+5; // expected-error {{arithmetic on pointer to incomplete type 'I0 *'}}
+ P = P+5; // expected-error {{arithmetic on a pointer to an incomplete type 'I0'}}
return &P[4]; // expected-error{{subscript of pointer to incomplete type 'I0'}}
}
diff --git a/test/SemaObjC/special-dep-unavail-warning.m b/test/SemaObjC/special-dep-unavail-warning.m
index 1d07a49e619d..57a2fa346569 100644
--- a/test/SemaObjC/special-dep-unavail-warning.m
+++ b/test/SemaObjC/special-dep-unavail-warning.m
@@ -3,24 +3,24 @@
@interface B
- (void) depInA;
-- (void) unavailMeth __attribute__((unavailable)); // expected-note {{function has been explicitly marked unavailable here}}
+- (void) unavailMeth __attribute__((unavailable)); // expected-note {{has been explicitly marked unavailable here}}
- (void) depInA1 __attribute__((deprecated));
- (void) unavailMeth1;
- (void) depInA2 __attribute__((deprecated));
-- (void) unavailMeth2 __attribute__((unavailable)); // expected-note {{function has been explicitly marked unavailable here}}
+- (void) unavailMeth2 __attribute__((unavailable)); // expected-note {{has been explicitly marked unavailable here}}
- (void) depunavailInA;
-- (void) depunavailInA1 __attribute__((deprecated)) __attribute__((unavailable)); // expected-note {{function has been explicitly marked unavailable here}}
+- (void) depunavailInA1 __attribute__((deprecated)) __attribute__((unavailable)); // expected-note {{has been explicitly marked unavailable here}}
- (void)FuzzyMeth __attribute__((deprecated));
- (void)FuzzyMeth1 __attribute__((unavailable));
@end
@interface A
-- (void) unavailMeth1 __attribute__((unavailable)); // expected-note {{function has been explicitly marked unavailable here}}
+- (void) unavailMeth1 __attribute__((unavailable)); // expected-note {{has been explicitly marked unavailable here}}
- (void) depInA __attribute__((deprecated));
- (void) depInA2 __attribute__((deprecated));
- (void) depInA1;
- (void) unavailMeth2 __attribute__((unavailable));
-- (void) depunavailInA __attribute__((deprecated)) __attribute__((unavailable)); // expected-note {{function has been explicitly marked unavailable here}}
+- (void) depunavailInA __attribute__((deprecated)) __attribute__((unavailable)); // expected-note {{has been explicitly marked unavailable here}}
- (void) depunavailInA1;
- (void)FuzzyMeth __attribute__((unavailable));
- (void)FuzzyMeth1 __attribute__((deprecated));
diff --git a/test/SemaObjC/synthesized-ivar.m b/test/SemaObjC/synthesized-ivar.m
index 3bc372bcd81e..4786d808fa2f 100644
--- a/test/SemaObjC/synthesized-ivar.m
+++ b/test/SemaObjC/synthesized-ivar.m
@@ -51,3 +51,11 @@ int f0(I *a) { return a->IP; } // expected-error {{instance variable 'IP' is pri
}
@end
+@interface A
+@property (weak) id testObjectWeakProperty; // expected-note {{declared here}}
+@end
+
+@implementation A
+// rdar://9605088
+@synthesize testObjectWeakProperty; // expected-error {{@synthesize of 'weak' property is only allowed in ARC or GC mode}}
+@end
diff --git a/test/SemaObjC/typedef-class.m b/test/SemaObjC/typedef-class.m
index 0f7e6822c4f9..c983195b243e 100644
--- a/test/SemaObjC/typedef-class.m
+++ b/test/SemaObjC/typedef-class.m
@@ -5,7 +5,7 @@ typedef struct _NSZone NSZone;
@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
-@protocol NSObject - (BOOL) isEqual:(id) object; @end
+@protocol NSObject - (BOOL) isEqual:(id) object; - (id)init; @end
@protocol NSCopying - (id) copyWithZone:(NSZone *) zone; @end
@protocol NSCoding - (void) encodeWithCoder:(NSCoder *) aCoder; @end
diff --git a/test/SemaObjC/undef-superclass-1.m b/test/SemaObjC/undef-superclass-1.m
index c941f82e435c..41cf1439bd9c 100644
--- a/test/SemaObjC/undef-superclass-1.m
+++ b/test/SemaObjC/undef-superclass-1.m
@@ -1,8 +1,8 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-@class SUPER, Y;
+@class SUPER, Y; // expected-note 2 {{forward class is declared here}}
-@interface INTF :SUPER // expected-error {{cannot find interface declaration for 'SUPER', superclass of 'INTF'}}
+@interface INTF :SUPER // expected-error {{attempting to use the forward class 'SUPER' as superclass of 'INTF'}}
@end
@interface SUPER @end
@@ -13,7 +13,7 @@
@interface INTF2 : INTF1
@end
-@interface INTF3 : Y // expected-error {{cannot find interface declaration for 'Y', superclass of 'INTF3'}} \
+@interface INTF3 : Y // expected-error {{attempting to use the forward class 'Y' as superclass of 'INTF3'}} \
// expected-note{{'INTF3' declared here}}
@end
diff --git a/test/SemaObjC/warn-retain-cycle.m b/test/SemaObjC/warn-retain-cycle.m
new file mode 100644
index 000000000000..71385b8400bb
--- /dev/null
+++ b/test/SemaObjC/warn-retain-cycle.m
@@ -0,0 +1,91 @@
+// RUN: %clang_cc1 -fsyntax-only -fobjc-nonfragile-abi -fobjc-runtime-has-weak -fobjc-arc -fblocks -verify %s
+
+@interface Test0
+- (void) setBlock: (void(^)(void)) block;
+- (void) addBlock: (void(^)(void)) block;
+- (void) actNow;
+@end
+void test0(Test0 *x) {
+ [x setBlock: // expected-note {{block will be retained by the captured object}}
+ ^{ [x actNow]; }]; // expected-warning {{capturing 'x' strongly in this block is likely to lead to a retain cycle}}
+ x.block = // expected-note {{block will be retained by the captured object}}
+ ^{ [x actNow]; }; // expected-warning {{capturing 'x' strongly in this block is likely to lead to a retain cycle}}
+
+ [x addBlock: // expected-note {{block will be retained by the captured object}}
+ ^{ [x actNow]; }]; // expected-warning {{capturing 'x' strongly in this block is likely to lead to a retain cycle}}
+
+ // These actually don't cause retain cycles.
+ __weak Test0 *weakx = x;
+ [x addBlock: ^{ [weakx actNow]; }];
+ [x setBlock: ^{ [weakx actNow]; }];
+ x.block = ^{ [weakx actNow]; };
+
+ // These do cause retain cycles, but we're not clever enough to figure that out.
+ [weakx addBlock: ^{ [x actNow]; }];
+ [weakx setBlock: ^{ [x actNow]; }];
+ weakx.block = ^{ [x actNow]; };
+}
+
+@interface BlockOwner
+@property (retain) void (^strong)(void);
+@end
+
+@interface Test1 {
+@public
+ BlockOwner *owner;
+};
+@property (retain) BlockOwner *owner;
+@property (assign) __strong BlockOwner *owner2; // expected-error {{unsafe_unretained property 'owner2' may not also be declared __strong}}
+@property (assign) BlockOwner *owner3;
+@end
+void test1(Test1 *x) {
+ x->owner.strong = ^{ (void) x; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}}
+ x.owner.strong = ^{ (void) x; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}}
+ x.owner2.strong = ^{ (void) x; };
+ x.owner3.strong = ^{ (void) x; };
+}
+
+@implementation Test1 {
+ BlockOwner * __unsafe_unretained owner3ivar;
+ __weak BlockOwner *weakowner;
+}
+@dynamic owner;
+@dynamic owner2;
+@synthesize owner3 = owner3ivar;
+
+- (id) init {
+ self.owner.strong = ^{ (void) owner; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}}
+ self.owner2.strong = ^{ (void) owner; };
+
+ // TODO: should we warn here? What's the story with this kind of mismatch?
+ self.owner3.strong = ^{ (void) owner; };
+
+ owner.strong = ^{ (void) owner; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}}
+
+ owner.strong = ^{ ^{ (void) owner; }(); }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}}
+
+ owner.strong = ^{ (void) sizeof(self); // expected-note {{block will be retained by an object strongly retained by the captured object}}
+ (void) owner; }; // expected-warning {{capturing 'self' strongly in this block is likely to lead to a retain cycle}}
+
+ weakowner.strong = ^{ (void) owner; };
+
+ return self;
+}
+- (void) foo {
+ owner.strong = ^{ (void) owner; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}}
+}
+@end
+
+void test2_helper(id);
+@interface Test2 {
+ void (^block)(void);
+ id x;
+}
+@end
+@implementation Test2
+- (void) test {
+ block = ^{ // expected-note {{block will be retained by an object strongly retained by the captured object}}
+ test2_helper(x); // expected-warning {{capturing 'self' strongly in this block is likely to lead to a retain cycle}}
+ };
+}
+@end
diff --git a/test/SemaObjC/weak-property.m b/test/SemaObjC/weak-property.m
new file mode 100644
index 000000000000..f0006076413d
--- /dev/null
+++ b/test/SemaObjC/weak-property.m
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -fsyntax-only -fobjc-nonfragile-abi -fobjc-runtime-has-weak -fobjc-arc -verify %s
+// rdar://8899430
+
+@interface WeakPropertyTest {
+ Class isa;
+ __weak id value;
+ id x;
+}
+@property (weak) id value1;
+@property __weak id value;
+@property () __weak id value2;
+
+@property (weak, assign) id v1; // expected-error {{property attributes 'assign' and 'weak' are mutually exclusive}}
+@property (weak, copy) id v2; // expected-error {{property attributes 'copy' and 'weak' are mutually exclusive}}
+@property (weak, retain) id v3; // expected-error {{property attributes 'retain' and 'weak' are mutually exclusive}}
+@property (weak, assign) id v4; // expected-error {{property attributes 'assign' and 'weak' are mutually exclusive}}
+
+@property () __weak id x; // expected-note {{property declared here}}
+@end
+
+@implementation WeakPropertyTest
+@synthesize x; // expected-error {{existing ivar 'x' for __weak property 'x' must be __weak}}
+@dynamic value1, value, value2, v1,v2,v3,v4;
+@end
diff --git a/test/SemaObjCXX/Inputs/arc-system-header.h b/test/SemaObjCXX/Inputs/arc-system-header.h
new file mode 100644
index 000000000000..d7adeb4d4008
--- /dev/null
+++ b/test/SemaObjCXX/Inputs/arc-system-header.h
@@ -0,0 +1,14 @@
+@interface B
+@end
+
+
+@interface A {
+@public
+ union {
+ struct {
+ B *b;
+ } a_b;
+ void *void_ptr;
+ } data;
+}
+@end
diff --git a/test/SemaObjCXX/arc-0x.mm b/test/SemaObjCXX/arc-0x.mm
new file mode 100644
index 000000000000..fa022af522e9
--- /dev/null
+++ b/test/SemaObjCXX/arc-0x.mm
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -std=c++0x -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -verify -fblocks -fobjc-exceptions %s
+
+// "Move" semantics, trivial version.
+void move_it(__strong id &&from) {
+ id to = static_cast<__strong id&&>(from);
+}
+
+// Deduction with 'auto'.
+@interface A
++ alloc;
+- init;
+@end
+
+// Ensure that deduction works with lifetime qualifiers.
+void deduction(id obj) {
+ auto a = [[A alloc] init];
+ __strong A** aPtr = &a;
+
+ auto a2([[A alloc] init]);
+ __strong A** aPtr2 = &a2;
+
+ __strong id *idp = new auto(obj);
+
+ __strong id array[17];
+ for (auto x : array) {
+ __strong id *xPtr = &x;
+ }
+
+ @try {
+ } @catch (auto e) { // expected-error {{'auto' not allowed in exception declaration}}
+ }
+}
diff --git a/test/SemaObjCXX/arc-bool-conversion.mm b/test/SemaObjCXX/arc-bool-conversion.mm
new file mode 100644
index 000000000000..86da3ca90cf1
--- /dev/null
+++ b/test/SemaObjCXX/arc-bool-conversion.mm
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -verify -fblocks -triple x86_64-apple-darwin10.0.0 %s
+// rdar://9310049
+
+bool fn(id obj) {
+ return (bool)obj;
+}
+
diff --git a/test/SemaObjCXX/arc-bridged-cast.mm b/test/SemaObjCXX/arc-bridged-cast.mm
new file mode 100644
index 000000000000..cbbe79eb2744
--- /dev/null
+++ b/test/SemaObjCXX/arc-bridged-cast.mm
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -fblocks -verify %s
+
+typedef const void *CFTypeRef;
+typedef const struct __CFString *CFStringRef;
+
+@interface NSString
+@end
+
+CFTypeRef CFCreateSomething();
+CFStringRef CFCreateString();
+CFTypeRef CFGetSomething();
+CFStringRef CFGetString();
+
+id CreateSomething();
+NSString *CreateNSString();
+
+template<typename IdType, typename StringType, typename IntPtrType>
+void from_cf() {
+ id obj1 = (__bridge_transfer IdType)CFCreateSomething();
+ id obj2 = (__bridge_transfer StringType)CFCreateString();
+ (__bridge IntPtrType)CFCreateSomething(); // expected-error{{incompatible types casting 'CFTypeRef' (aka 'const void *') to 'int *' with a __bridge cast}}
+ id obj3 = (__bridge IdType)CFGetSomething();
+ id obj4 = (__bridge StringType)CFGetString();
+}
+
+template void from_cf<id, NSString*, int*>(); // expected-note{{in instantiation of function template specialization}}
+
+template<typename IdType, typename StringType>
+void to_cf(id obj) {
+ CFTypeRef cf1 = (__bridge_retained IdType)CreateSomething();
+ CFStringRef cf2 = (__bridge_retained StringType)CreateNSString();
+ CFTypeRef cf3 = (__bridge IdType)CreateSomething();
+ CFStringRef cf4 = (__bridge StringType)CreateNSString();
+}
+
+template void to_cf<CFTypeRef, CFStringRef>(id);
diff --git a/test/SemaObjCXX/arc-libcxx.mm b/test/SemaObjCXX/arc-libcxx.mm
new file mode 100644
index 000000000000..7992f602f51a
--- /dev/null
+++ b/test/SemaObjCXX/arc-libcxx.mm
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -fobjc-arc-cxxlib=libc++ -fobjc-nonfragile-abi -fobjc-runtime-has-weak -verify %s
+
+@interface A @end
+
+void f(__strong id &sir, __weak id &wir, __autoreleasing id &air,
+ __unsafe_unretained id &uir) {
+ __strong id *sip = std::addressof(sir);
+ __weak id *wip = std::addressof(wir);
+ __autoreleasing id *aip = std::addressof(air);
+ __unsafe_unretained id *uip = std::addressof(uir);
+}
diff --git a/test/SemaObjCXX/arc-libstdcxx.mm b/test/SemaObjCXX/arc-libstdcxx.mm
new file mode 100644
index 000000000000..edb7a9ef486a
--- /dev/null
+++ b/test/SemaObjCXX/arc-libstdcxx.mm
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -fobjc-arc-cxxlib=libstdc++ -fobjc-nonfragile-abi -fobjc-runtime-has-weak -verify %s
+
+@interface A @end
+
+int check0[std::__is_scalar<__strong id>::__value? -1 : 1];
+int check1[std::__is_scalar<__weak id>::__value? -1 : 1];
+int check2[std::__is_scalar<__autoreleasing id>::__value? -1 : 1];
+int check3[std::__is_scalar<__strong A*>::__value? -1 : 1];
+int check4[std::__is_scalar<__weak A*>::__value? -1 : 1];
+int check5[std::__is_scalar<__autoreleasing A*>::__value? -1 : 1];
diff --git a/test/SemaObjCXX/arc-memfunc.mm b/test/SemaObjCXX/arc-memfunc.mm
new file mode 100644
index 000000000000..75b94c64e727
--- /dev/null
+++ b/test/SemaObjCXX/arc-memfunc.mm
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -verify -fblocks %s
+
+struct X0 {
+ static id makeObject1() __attribute__((ns_returns_retained));
+ id makeObject2() __attribute__((ns_returns_retained));
+};
+
+void test_X0(X0 x0, X0 *x0p) {
+ X0::makeObject1();
+ x0.makeObject2();
+ x0p->makeObject2();
+ id (X0::*pmf)() __attribute__((ns_returns_retained)) = &X0::makeObject2;
+ (x0.*pmf)();
+ (x0p->*pmf)();
+}
diff --git a/test/SemaObjCXX/arc-non-pod.mm b/test/SemaObjCXX/arc-non-pod.mm
new file mode 100644
index 000000000000..6a47b3d85664
--- /dev/null
+++ b/test/SemaObjCXX/arc-non-pod.mm
@@ -0,0 +1,116 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -Warc-abi -verify -fblocks -triple x86_64-apple-darwin10.0.0 %s
+
+// Classes that have an Objective-C object pointer.
+struct HasObjectMember0 { // expected-warning{{'HasObjectMember0' cannot be shared between ARC and non-ARC code; add a copy constructor, a copy assignment operator, and a destructor to make it ABI-compatible}}
+ id x;
+};
+
+struct HasObjectMember1 { // expected-warning{{'HasObjectMember1' 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}}
+ id x[3];
+};
+
+struct HasObjectMember2 { // expected-warning{{'HasObjectMember2' 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}}
+ id x[3][2];
+};
+
+// Don't complain if the type has non-external linkage
+namespace {
+ struct HasObjectMember3 {
+ id x[3][2];
+ };
+}
+
+// Don't complain if the Objective-C pointer type was explicitly given
+// no ownership.
+struct HasObjectMember3 {
+ __unsafe_unretained id x[3][2];
+};
+
+struct HasBlockPointerMember0 { // expected-warning{{'HasBlockPointerMember0' 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}}
+ int (^bp)(int);
+};
+
+struct HasBlockPointerMember1 { // expected-warning{{'HasBlockPointerMember1' 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}}
+ int (^bp[2][3])(int);
+};
+
+struct NonPOD {
+ NonPOD(const NonPOD&);
+};
+
+struct HasObjectMemberAndNonPOD0 { // expected-warning{{'HasObjectMemberAndNonPOD0' cannot be shared between ARC and non-ARC code; add a non-trivial copy assignment operator to make it ABI-compatible}} \
+ // expected-warning{{'HasObjectMemberAndNonPOD0' cannot be shared between ARC and non-ARC code; add a non-trivial destructor to make it ABI-compatible}}
+ id x;
+ NonPOD np;
+};
+
+struct HasObjectMemberAndNonPOD1 { // expected-warning{{'HasObjectMemberAndNonPOD1' cannot be shared between ARC and non-ARC code; add a non-trivial copy assignment operator to make it ABI-compatible}} \
+ // expected-warning{{'HasObjectMemberAndNonPOD1' cannot be shared between ARC and non-ARC code; add a non-trivial destructor to make it ABI-compatible}}
+ NonPOD np;
+ id x[3];
+};
+
+struct HasObjectMemberAndNonPOD2 { // expected-warning{{'HasObjectMemberAndNonPOD2' cannot be shared between ARC and non-ARC code; add a non-trivial copy assignment operator to make it ABI-compatible}} \
+ // expected-warning{{'HasObjectMemberAndNonPOD2' cannot be shared between ARC and non-ARC code; add a non-trivial destructor to make it ABI-compatible}}
+ NonPOD np;
+ id x[3][2];
+};
+
+struct HasObjectMemberAndNonPOD3 {
+ HasObjectMemberAndNonPOD3 &operator=(const HasObjectMemberAndNonPOD3&);
+ ~HasObjectMemberAndNonPOD3();
+ NonPOD np;
+ id x[3][2];
+};
+
+struct HasBlockPointerMemberAndNonPOD0 { // expected-warning{{'HasBlockPointerMemberAndNonPOD0' cannot be shared between ARC and non-ARC code; add a non-trivial copy assignment operator to make it ABI-compatible}} \
+// expected-warning{{'HasBlockPointerMemberAndNonPOD0' cannot be shared between ARC and non-ARC code; add a non-trivial destructor to make it ABI-compatible}}
+ NonPOD np;
+ int (^bp)(int);
+};
+
+struct HasBlockPointerMemberAndNonPOD1 { // expected-warning{{'HasBlockPointerMemberAndNonPOD1' cannot be shared between ARC and non-ARC code; add a non-trivial copy assignment operator to make it ABI-compatible}} \
+// expected-warning{{'HasBlockPointerMemberAndNonPOD1' cannot be shared between ARC and non-ARC code; add a non-trivial destructor to make it ABI-compatible}}
+ NonPOD np;
+ int (^bp[2][3])(int);
+};
+
+int check_non_pod_objc_pointer0[__is_pod(id)? 1 : -1];
+int check_non_pod_objc_pointer1[__is_pod(__strong id)? -1 : 1];
+int check_non_pod_objc_pointer2[__is_pod(__unsafe_unretained id)? 1 : -1];
+int check_non_pod_objc_pointer3[__is_pod(id[2][3])? 1 : -1];
+int check_non_pod_objc_pointer4[__is_pod(__unsafe_unretained id[2][3])? 1 : -1];
+int check_non_pod_block0[__is_pod(int (^)(int))? 1 : -1];
+int check_non_pod_block1[__is_pod(int (^ __unsafe_unretained)(int))? 1 : -1];
+int check_non_pod_block2[__is_pod(int (^ __strong)(int))? -1 : 1];
+
+struct FlexibleArrayMember0 {
+ int length;
+ id array[]; // expected-error{{flexible array member 'array' of non-POD element type 'id __strong[]'}}
+};
+
+struct FlexibleArrayMember1 {
+ int length;
+ __unsafe_unretained id array[];
+};
+
+// It's okay to pass a retainable type through an ellipsis.
+void variadic(...);
+void test_variadic() {
+ variadic(1, 17, @"Foo");
+}
+
+// It's okay to create a VLA of retainable types.
+void vla(int n) {
+ id vla[n];
+}
+
+@interface Crufty {
+ union {
+ struct {
+ id object; // expected-note{{has __strong ownership}}
+ } an_object; // expected-error{{union member 'an_object' has a non-trivial copy constructor}}
+ void *ptr;
+ } storage;
+}
+@end
diff --git a/test/SemaObjCXX/arc-object-init-destroy.mm b/test/SemaObjCXX/arc-object-init-destroy.mm
new file mode 100644
index 000000000000..196f49371847
--- /dev/null
+++ b/test/SemaObjCXX/arc-object-init-destroy.mm
@@ -0,0 +1,52 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -verify -Warc-abi -fblocks -triple x86_64-apple-darwin10.0.0 %s
+
+typedef __strong id strong_id;
+typedef __weak id weak_id;
+void test_pseudo_destructors(__strong id *sptr, __weak id *wptr) {
+ sptr->~id(); // okay
+ wptr->~id(); // okay
+ sptr->~strong_id(); // okay
+ wptr->~weak_id();
+ sptr->~weak_id(); // expected-error{{pseudo-destructor destroys object of type '__strong id' with inconsistently-qualified type 'weak_id' (aka '__weak id')}}
+ wptr->strong_id::~strong_id(); // expected-error{{pseudo-destructor destroys object of type '__weak id' with inconsistently-qualified type 'strong_id' (aka '__strong id')}}
+
+ sptr->id::~id(); // okay
+ wptr->id::~id(); // okay
+}
+
+void test_delete(__strong id *sptr, __weak id *wptr) {
+ delete sptr;
+ delete wptr;
+ delete [] sptr; // expected-warning{{destroying an array of '__strong id'; this array must not have been allocated from non-ARC code}}
+ delete [] wptr; // expected-warning{{destroying an array of '__weak id'; this array must not have been allocated from non-ARC code}}
+}
+
+void test_new(int n) {
+ (void)new strong_id;
+ (void)new weak_id;
+ (void)new strong_id [n]; // expected-warning{{allocating an array of 'strong_id' (aka '__strong id'); this array must not be deleted in non-ARC code}}
+ (void)new weak_id [n]; // expected-warning{{allocating an array of 'weak_id' (aka '__weak id'); this array must not be deleted in non-ARC code}}
+
+ (void)new __strong id;
+ (void)new __weak id;
+ (void)new __strong id [n]; // expected-warning{{allocating an array of '__strong id'; this array must not be deleted in non-ARC code}}
+
+ // Infer '__strong'.
+ __strong id *idptr = new id;
+ __strong id *idptr2 = new id [n]; // expected-warning{{allocating an array of '__strong id'; this array must not be deleted in non-ARC code}}
+
+ // ... but not for arrays.
+ typedef id id_array[2][3];
+ (void)new id_array; // expected-error{{'new' cannot allocate an array of 'id' with no explicit ownership}}
+
+ typedef __strong id strong_id_array[2][3];
+ typedef __strong id strong_id_3[3];
+ strong_id_3 *idptr3 = new strong_id_array; // expected-warning{{allocating an array of '__strong id'; this array must not be deleted in non-ARC code}}
+}
+
+void test_jump_scope() {
+ goto done; // expected-error{{goto into protected scope}}
+ __strong id x; // expected-note{{jump bypasses initialization of retaining variable}}
+ done:
+ return;
+}
diff --git a/test/SemaObjCXX/arc-overloading.mm b/test/SemaObjCXX/arc-overloading.mm
new file mode 100644
index 000000000000..06b332cec85f
--- /dev/null
+++ b/test/SemaObjCXX/arc-overloading.mm
@@ -0,0 +1,175 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -verify -fblocks %s
+
+// Simple ownership conversions + diagnostics.
+int &f0(id __strong const *); // expected-note{{candidate function not viable: 1st argument ('__weak id *') has __weak ownership, but parameter has __strong ownership}}
+
+void test_f0() {
+ id __strong *sip;
+ id __strong const *csip;
+ id __weak *wip;
+ id __autoreleasing *aip;
+ id __unsafe_unretained *uip;
+
+ int &ir1 = f0(sip);
+ int &ir2 = f0(csip);
+ int &ir3 = f0(aip);
+ int &ir4 = f0(uip);
+ f0(wip); // expected-error{{no matching function for call to 'f0'}}
+}
+
+// Simple overloading
+int &f1(id __strong const *);
+float &f1(id __weak const *);
+
+void test_f1() {
+ id __strong *sip;
+ id __strong const *csip;
+ id __weak *wip;
+ id __autoreleasing *aip;
+ id __unsafe_unretained *uip;
+
+ int &ir1 = f1(sip);
+ int &ir2 = f1(csip);
+ float &fr1 = f1(wip);
+ int &ir3 = f1(aip);
+ int &ir4 = f1(uip);
+}
+
+// Simple overloading
+int &f2(id __strong const *); // expected-note{{candidate function}}
+float &f2(id __autoreleasing const *); // expected-note{{candidate function}}
+
+void test_f2() {
+ id __strong *sip;
+ id __strong const *csip;
+ id __weak *wip;
+ id __autoreleasing *aip;
+ id __unsafe_unretained *uip;
+
+ // Prefer non-ownership conversions to ownership conversions.
+ int &ir1 = f2(sip);
+ int &ir2 = f2(csip);
+ float &fr1 = f2(aip);
+
+ f2(uip); // expected-error{{call to 'f2' is ambiguous}}
+}
+
+// Writeback conversion
+int &f3(id __autoreleasing *); // expected-note{{candidate function not viable: 1st argument ('__unsafe_unretained id *') has __unsafe_unretained ownership, but parameter has __autoreleasing ownership}}
+
+void test_f3() {
+ id __strong sip;
+ id __weak wip;
+ id __autoreleasing aip;
+ id __unsafe_unretained uip;
+
+ int &ir1 = f3(&sip);
+ int &ir2 = f3(&wip);
+ int &ir3 = f3(&aip);
+ f3(&uip); // expected-error{{no matching function for call to 'f3'}}
+}
+
+// Writeback conversion vs. no conversion
+int &f4(id __autoreleasing *);
+float &f4(id __strong *);
+
+void test_f4() {
+ id __strong sip;
+ id __weak wip;
+ id __autoreleasing aip;
+ extern __weak id weak_global_ptr;
+
+ float &fr1 = f4(&sip);
+ int &ir1 = f4(&wip);
+ int &ir2 = f4(&aip);
+ int &ir3 = f4(&weak_global_ptr); // expected-error{{passing address of non-local object to __autoreleasing parameter for write-back}}
+}
+
+// Writeback conversion vs. other conversion.
+int &f5(id __autoreleasing *);
+float &f5(id const __unsafe_unretained *);
+
+void test_f5() {
+ id __strong sip;
+ id __weak wip;
+ id __autoreleasing aip;
+
+ int &ir1 = f5(&wip);
+ float &fr1 = f5(&sip);
+ int &ir2 = f5(&aip);
+}
+
+@interface A
+@end
+
+int &f6(id __autoreleasing *);
+float &f6(id const __unsafe_unretained *);
+
+void test_f6() {
+ A* __strong sip;
+ A* __weak wip;
+ A* __autoreleasing aip;
+
+ int &ir1 = f6(&wip);
+ float &fr1 = f6(&sip);
+ int &ir2 = f6(&aip);
+}
+
+// Reference binding
+void f7(__strong id&); // expected-note{{candidate function not viable: 1st argument ('__weak id') has __weak ownership, but parameter has __strong ownership}} \
+ // expected-note{{candidate function not viable: 1st argument ('__autoreleasing id') has __autoreleasing ownership, but parameter has __strong ownership}} \
+ // expected-note{{candidate function not viable: 1st argument ('__unsafe_unretained id') has __unsafe_unretained ownership, but parameter has __strong ownership}}
+
+void test_f7() {
+ __strong id strong_id;
+ __weak id weak_id;
+ __autoreleasing id autoreleasing_id;
+ __unsafe_unretained id unsafe_id;
+ f7(strong_id);
+ f7(weak_id); // expected-error{{no matching function for call to 'f7'}}
+ f7(autoreleasing_id); // expected-error{{no matching function for call to 'f7'}}
+ f7(unsafe_id); // expected-error{{no matching function for call to 'f7'}}
+}
+
+void f8(const __strong id&);
+
+void test_f8() {
+ __strong id strong_id;
+ __weak id weak_id;
+ __autoreleasing id autoreleasing_id;
+ __unsafe_unretained id unsafe_id;
+
+ f8(strong_id);
+ f8(weak_id);
+ f8(autoreleasing_id);
+ f8(unsafe_id);
+}
+
+int &f9(__strong id&);
+float &f9(const __autoreleasing id&);
+
+void test_f9() {
+ __strong id strong_id;
+ __weak id weak_id;
+ __autoreleasing id autoreleasing_id;
+ __unsafe_unretained id unsafe_id;
+
+ int &ir1 = f9(strong_id);
+ float &fr1 = f9(autoreleasing_id);
+ float &fr2 = f9(unsafe_id);
+ float &fr2a = f9(weak_id);
+
+ __strong A *strong_a;
+ __weak A *weak_a;
+ __autoreleasing A *autoreleasing_a;
+ __unsafe_unretained A *unsafe_unretained_a;
+ float &fr3 = f9(strong_a);
+ float &fr4 = f9(autoreleasing_a);
+ float &fr5 = f9(unsafe_unretained_a);
+ float &fr6 = f9(weak_a);
+
+ const __autoreleasing id& ar1 = strong_a;
+ const __autoreleasing id& ar2 = autoreleasing_a;
+ const __autoreleasing id& ar3 = unsafe_unretained_a;
+ const __autoreleasing id& ar4 = weak_a;
+}
diff --git a/test/SemaObjCXX/arc-system-header.mm b/test/SemaObjCXX/arc-system-header.mm
new file mode 100644
index 000000000000..cb2b85868ce1
--- /dev/null
+++ b/test/SemaObjCXX/arc-system-header.mm
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -fobjc-arc -fobjc-nonfragile-abi -isystem %S/Inputs %s -verify
+
+#include <arc-system-header.h>
+
+void f(A* a) {
+ a->data.void_ptr = 0;
+ a->data.a_b.b = 0; // expected-error{{'a_b' is unavailable: this system field has retaining ownership}}
+}
+// Silly location below
+// expected-note{{declaration has been explicitly marked unavailable here}}
diff --git a/test/SemaObjCXX/arc-templates.mm b/test/SemaObjCXX/arc-templates.mm
new file mode 100644
index 000000000000..fa4e0a777642
--- /dev/null
+++ b/test/SemaObjCXX/arc-templates.mm
@@ -0,0 +1,254 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -verify -fblocks %s
+
+@interface A
+@end
+
+template<typename T, typename U>
+struct is_same {
+ static const bool value = false;
+};
+
+template<typename T>
+struct is_same<T, T> {
+ static const bool value = true;
+};
+
+// Instantiation for reference/pointer types that will get lifetime
+// adjustments.
+template<typename T>
+struct X0 {
+ typedef T* pointer; // okay: ends up being strong.
+ typedef T& reference; // okay: ends up being strong
+};
+
+void test_X0() {
+ X0<id> x0id;
+ X0<A*> x0a;
+ X0<__strong A*> x0sa;
+
+ id __strong *ptr;
+ id __strong val;
+ X0<__strong id>::pointer &ptr_ref = ptr;
+ X0<__strong id>::reference ref = val;
+}
+
+int check_infer_strong[is_same<id, __strong id>::value? 1 : -1];
+
+// Check template argument deduction (e.g., for specialization) using
+// lifetime qualifiers.
+template<typename T>
+struct is_pointer_strong {
+ static const bool value = false;
+};
+
+template<typename T>
+struct is_pointer_strong<__strong T*> {
+ static const bool value = true;
+};
+
+int check_ptr_strong1[is_pointer_strong<__strong id*>::value? 1 : -1];
+int check_ptr_strong2[is_pointer_strong<__weak id*>::value? -1 : 1];
+int check_ptr_strong3[is_pointer_strong<__autoreleasing id*>::value? -1 : 1];
+int check_ptr_strong4[is_pointer_strong<__unsafe_unretained id*>::value? -1 : 1];
+int check_ptr_strong5[is_pointer_strong<id>::value? -1 : 1];
+
+// Check substitution into lifetime-qualified dependent types.
+template<typename T>
+struct make_strong_pointer {
+ typedef __strong T *type;
+};
+
+template<typename T>
+struct make_strong_pointer<__weak T> {
+ typedef __strong T *type;
+};
+
+template<typename T>
+struct make_strong_pointer<__autoreleasing T> {
+ typedef __strong T *type;
+};
+
+template<typename T>
+struct make_strong_pointer<__unsafe_unretained T> {
+ typedef __strong T *type;
+};
+
+// Adding qualifiers
+int check_make_strong1[is_same<make_strong_pointer<id>::type, __strong id *>::value ? 1 : -1];
+int check_make_strong2[is_same<make_strong_pointer<A*>::type, A* __strong *>::value ? 1 : -1];
+
+// Adding redundant qualifiers
+int check_make_strong3[is_same<make_strong_pointer<__strong id>::type, __strong id *>::value ? 1 : -1];
+int check_make_strong4[is_same<make_strong_pointer<__strong A*>::type, A* __strong *>::value ? 1 : -1];
+
+// Adding nonsensical qualifiers.
+int check_make_strong5[is_same<make_strong_pointer<int>::type, int *>::value ? 1 : -1];
+int check_make_strong6[is_same<make_strong_pointer<__weak id>::type, __strong id *>::value ? 1 : -1];
+
+template<typename T>
+struct make_weak {
+ typedef __weak T type;
+};
+
+int check_make_weak0[is_same<make_weak<id>::type, __weak id>::value? 1 : -1];
+int check_make_weak1[is_same<make_weak<__strong id>::type, __weak id>::value? 1 : -1];
+int check_make_weak2[is_same<make_weak<__autoreleasing id>::type, __weak id>::value? 1 : -1];
+
+template<typename T>
+struct make_weak_fail {
+ typedef T T_type;
+ typedef __weak T_type type; // expected-error{{the type 'T_type' (aka '__weak id') already has retainment attributes set on it}} \
+ // expected-error{{the type 'T_type' (aka '__strong id') already has retainment attributes set on it}}
+};
+
+int check_make_weak_fail0[is_same<make_weak_fail<__weak id>::type, __weak id>::value? 1 : -1]; // expected-note{{in instantiation of template class 'make_weak_fail<__weak id>' requested here}}
+
+int check_make_weak_fail1[is_same<make_weak_fail<id>::type, __weak id>::value? -1 : 1]; // expected-note{{in instantiation of template class 'make_weak_fail<id>' requested here}}
+
+// Check template argument deduction from function templates.
+template<typename T> struct identity { };
+
+template<typename T> identity<T> accept_strong_ptr(__strong T*);
+template<typename T> identity<T> accept_strong_ref(__strong T&);
+
+template<typename T> identity<T> accept_any_ptr(T*);
+template<typename T> identity<T> accept_any_ref(T&);
+
+void test_func_deduction_id() {
+ __strong id *sip;
+ __weak id *wip;
+ __autoreleasing id *aip;
+ __unsafe_unretained id *uip;
+
+ identity<id> res1 = accept_strong_ptr(sip);
+ identity<__strong id> res2 = accept_any_ptr(sip);
+
+ __strong id si;
+ __weak id wi;
+ __autoreleasing id ai;
+ __unsafe_unretained id ui;
+ identity<id> res3 = accept_strong_ref(si);
+ identity<__strong id> res4 = accept_any_ref(si);
+ identity<__weak id> res5 = accept_any_ref(wi);
+ identity<__autoreleasing id> res6 = accept_any_ref(ai);
+ identity<__unsafe_unretained id> res7 = accept_any_ref(ui);
+}
+
+void test_func_deduction_A() {
+ __strong A * *sip;
+ __weak A * *wip;
+ __autoreleasing A * *aip;
+ __unsafe_unretained A * *uip;
+
+ identity<A *> res1 = accept_strong_ptr(sip);
+ identity<__strong A *> res2 = accept_any_ptr(sip);
+
+ __strong A * si;
+ __weak A * wi;
+ __autoreleasing A * ai;
+ __unsafe_unretained A * ui;
+ identity<A *> res3 = accept_strong_ref(si);
+ identity<__strong A *> res4 = accept_any_ref(si);
+ identity<__weak A *> res5 = accept_any_ref(wi);
+ identity<__autoreleasing A *> res6 = accept_any_ref(ai);
+ identity<__unsafe_unretained A *> res7 = accept_any_ref(ui);
+}
+
+// Test partial ordering (qualified vs. non-qualified).
+template<typename T>
+struct classify_pointer_pointer {
+ static const unsigned value = 0;
+};
+
+template<typename T>
+struct classify_pointer_pointer<T*> {
+ static const unsigned value = 1;
+};
+
+template<typename T>
+struct classify_pointer_pointer<__strong T*> {
+ static const unsigned value = 2;
+};
+
+template<typename T>
+struct classify_pointer_pointer<__weak T*> {
+ static const unsigned value = 3;
+};
+
+template<typename T>
+struct classify_pointer_pointer<T&> {
+ static const unsigned value = 4;
+};
+
+template<typename T>
+struct classify_pointer_pointer<__strong T&> {
+ static const unsigned value = 5;
+};
+
+template<typename T>
+struct classify_pointer_pointer<__weak T&> {
+ static const unsigned value = 6;
+};
+
+int classify_ptr1[classify_pointer_pointer<int>::value == 0? 1 : -1];
+int classify_ptr2[classify_pointer_pointer<int *>::value == 1? 1 : -1];
+int classify_ptr3[classify_pointer_pointer<id __strong *>::value == 2? 1 : -1];
+int classify_ptr4[classify_pointer_pointer<id __weak *>::value == 3? 1 : -1];
+int classify_ptr5[classify_pointer_pointer<int&>::value == 4? 1 : -1];
+int classify_ptr6[classify_pointer_pointer<id __strong&>::value == 5? 1 : -1];
+int classify_ptr7[classify_pointer_pointer<id __weak&>::value == 6? 1 : -1];
+int classify_ptr8[classify_pointer_pointer<id __autoreleasing&>::value == 4? 1 : -1];
+int classify_ptr9[classify_pointer_pointer<id __unsafe_unretained&>::value == 4? 1 : -1];
+int classify_ptr10[classify_pointer_pointer<id __autoreleasing *>::value == 1? 1 : -1];
+int classify_ptr11[classify_pointer_pointer<id __unsafe_unretained *>::value == 1? 1 : -1];
+int classify_ptr12[classify_pointer_pointer<int *>::value == 1? 1 : -1];
+int classify_ptr13[classify_pointer_pointer<A * __strong *>::value == 2? 1 : -1];
+int classify_ptr14[classify_pointer_pointer<A * __weak *>::value == 3? 1 : -1];
+int classify_ptr15[classify_pointer_pointer<int&>::value == 4? 1 : -1];
+int classify_ptr16[classify_pointer_pointer<A * __strong&>::value == 5? 1 : -1];
+int classify_ptr17[classify_pointer_pointer<A * __weak&>::value == 6? 1 : -1];
+int classify_ptr18[classify_pointer_pointer<A * __autoreleasing&>::value == 4? 1 : -1];
+int classify_ptr19[classify_pointer_pointer<A * __unsafe_unretained&>::value == 4? 1 : -1];
+int classify_ptr20[classify_pointer_pointer<A * __autoreleasing *>::value == 1? 1 : -1];
+int classify_ptr21[classify_pointer_pointer<A * __unsafe_unretained *>::value == 1? 1 : -1];
+
+template<typename T> int& qual_vs_unqual_ptr(__strong T*);
+template<typename T> double& qual_vs_unqual_ptr(__weak T*);
+template<typename T> float& qual_vs_unqual_ptr(T*);
+template<typename T> int& qual_vs_unqual_ref(__strong T&);
+template<typename T> double& qual_vs_unqual_ref(__weak T&);
+template<typename T> float& qual_vs_unqual_ref(T&);
+
+void test_qual_vs_unqual_id() {
+ __strong id *sip;
+ __weak id *wip;
+ __autoreleasing id *aip;
+ __unsafe_unretained id *uip;
+
+ int &ir1 = qual_vs_unqual_ptr(sip);
+ double &dr1 = qual_vs_unqual_ptr(wip);
+ float &fr1 = qual_vs_unqual_ptr(aip);
+ float &fr2 = qual_vs_unqual_ptr(uip);
+
+ int &ir2 = qual_vs_unqual_ref(*sip);
+ double &dr2 = qual_vs_unqual_ref(*wip);
+ float &fr3 = qual_vs_unqual_ref(*aip);
+ float &fr4 = qual_vs_unqual_ref(*uip);
+}
+
+void test_qual_vs_unqual_a() {
+ __strong A * *sap;
+ __weak A * *wap;
+ __autoreleasing A * *aap;
+ __unsafe_unretained A * *uap;
+
+ int &ir1 = qual_vs_unqual_ptr(sap);
+ double &dr1 = qual_vs_unqual_ptr(wap);
+ float &fr1 = qual_vs_unqual_ptr(aap);
+ float &fr2 = qual_vs_unqual_ptr(uap);
+
+ int &ir2 = qual_vs_unqual_ref(*sap);
+ double &dr2 = qual_vs_unqual_ref(*wap);
+ float &fr3 = qual_vs_unqual_ref(*aap);
+ float &fr4 = qual_vs_unqual_ref(*uap);
+}
diff --git a/test/SemaObjCXX/arc-type-conversion.mm b/test/SemaObjCXX/arc-type-conversion.mm
new file mode 100644
index 000000000000..f52f54a50cc4
--- /dev/null
+++ b/test/SemaObjCXX/arc-type-conversion.mm
@@ -0,0 +1,221 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -verify -fblocks %s
+// rdar://8843600
+
+void * cvt(id arg) // expected-note{{candidate function not viable: cannot convert argument of incomplete type 'void *' to '__strong id'}}
+{
+ void* voidp_val;
+ (void)(int*)arg; // expected-error {{cast of an Objective-C pointer to 'int *' is disallowed with ARC}}
+ (void)(id)arg;
+ (void)(__autoreleasing id*)arg; // expected-error{{C-style cast from 'id' to '__autoreleasing id *' casts away qualifiers}}
+ (void)(id*)arg; // expected-error{{C-style cast from 'id' to '__strong id *' casts away qualifiers}}
+
+ (void)(__autoreleasing id**)voidp_val;
+ (void)(void*)voidp_val;
+ (void)(void**)arg; // expected-error {{cast of an Objective-C pointer to 'void **' is disallowed}}
+ cvt((void*)arg); // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'void *' requires a bridged cast}} \
+ // expected-error {{no matching function for call to 'cvt'}} \
+ // expected-note{{use __bridge to convert directly (no change in ownership)}} \
+ // expected-note{{use __bridge_retained to make an ARC object available as a +1 'void *'}}
+ cvt(0);
+ (void)(__strong id**)(0);
+
+ // FIXME: Diagnostic could be better here.
+ return arg; // expected-error{{cannot initialize return object of type 'void *' with an lvalue of type '__strong id'}}
+}
+
+// rdar://8898937
+namespace rdar8898937 {
+
+typedef void (^dispatch_block_t)(void);
+
+void dispatch_once(dispatch_block_t block);
+static void _dispatch_once(dispatch_block_t block)
+{
+ dispatch_once(block);
+}
+
+}
+
+void static_casts(id arg) {
+ void* voidp_val;
+ (void)static_cast<int*>(arg); // expected-error {{cannot cast from type 'id' to pointer type 'int *'}}
+ (void)static_cast<id>(arg);
+ (void)static_cast<__autoreleasing id*>(arg); // expected-error{{cannot cast from type 'id' to pointer type '__autoreleasing id *'}}
+ (void)static_cast<id*>(arg); // expected-error {{cannot cast from type 'id' to pointer type '__strong id *'}}
+
+ (void)static_cast<__autoreleasing id**>(voidp_val);
+ (void)static_cast<void*>(voidp_val);
+ (void)static_cast<void**>(arg); // expected-error {{cannot cast from type 'id' to pointer type 'void **'}}
+ (void)static_cast<__strong id**>(0);
+
+ __strong id *idp;
+ (void)static_cast<__autoreleasing id*>(idp); // expected-error{{static_cast from '__strong id *' to '__autoreleasing id *' is not allowed}}
+ (void)static_cast<__weak id*>(idp); // expected-error{{static_cast from '__strong id *' to '__weak id *' is not allowed}}
+}
+
+void test_const_cast(__strong id *sip, __weak id *wip,
+ const __strong id *csip, __weak const id *cwip) {
+ // Cannot use const_cast to cast between ownership qualifications or
+ // add/remove ownership qualifications.
+ (void)const_cast<__strong id *>(wip); // expected-error{{is not allowed}}
+ (void)const_cast<__weak id *>(sip); // expected-error{{is not allowed}}
+
+ // It's acceptable to cast away constness.
+ (void)const_cast<__strong id *>(csip);
+ (void)const_cast<__weak id *>(cwip);
+}
+
+void test_reinterpret_cast(__strong id *sip, __weak id *wip,
+ const __strong id *csip, __weak const id *cwip) {
+ // Okay to reinterpret_cast to add/remove/change ownership
+ // qualifications.
+ (void)reinterpret_cast<__strong id *>(wip);
+ (void)reinterpret_cast<__weak id *>(sip);
+
+ // Not allowed to cast away constness
+ (void)reinterpret_cast<__strong id *>(csip); // expected-error{{reinterpret_cast from '__strong id const *' to '__strong id *' casts away qualifiers}}
+ (void)reinterpret_cast<__weak id *>(cwip); // expected-error{{reinterpret_cast from '__weak id const *' to '__weak id *' casts away qualifiers}}
+ (void)reinterpret_cast<__weak id *>(csip); // expected-error{{reinterpret_cast from '__strong id const *' to '__weak id *' casts away qualifiers}}
+ (void)reinterpret_cast<__strong id *>(cwip); // expected-error{{reinterpret_cast from '__weak id const *' to '__strong id *' casts away qualifiers}}
+}
+
+void test_cstyle_cast(__strong id *sip, __weak id *wip,
+ const __strong id *csip, __weak const id *cwip) {
+ // C-style casts aren't allowed to change Objective-C ownership
+ // qualifiers (beyond what the normal implicit conversion allows).
+
+ (void)(__strong id *)wip; // expected-error{{C-style cast from '__weak id *' to '__strong id *' casts away qualifiers}}
+ (void)(__strong id *)cwip; // expected-error{{C-style cast from '__weak id const *' to '__strong id *' casts away qualifiers}}
+ (void)(__weak id *)sip; // expected-error{{C-style cast from '__strong id *' to '__weak id *' casts away qualifiers}}
+ (void)(__weak id *)csip; // expected-error{{C-style cast from '__strong id const *' to '__weak id *' casts away qualifiers}}
+
+ (void)(__strong const id *)wip; // expected-error{{C-style cast from '__weak id *' to '__strong id const *' casts away qualifiers}}
+ (void)(__strong const id *)cwip; // expected-error{{C-style cast from '__weak id const *' to '__strong id const *' casts away qualifiers}}
+ (void)(__weak const id *)sip; // expected-error{{C-style cast from '__strong id *' to '__weak id const *' casts away qualifiers}}
+ (void)(__weak const id *)csip; // expected-error{{C-style cast from '__strong id const *' to '__weak id const *' casts away qualifiers}}
+ (void)(__autoreleasing const id *)wip; // expected-error{{C-style cast from '__weak id *' to '__autoreleasing id const *' casts away qualifiers}}
+ (void)(__autoreleasing const id *)cwip; // expected-error{{C-style cast from '__weak id const *' to '__autoreleasing id const *' casts away qualifiers}}
+ (void)(__autoreleasing const id *)sip;
+ (void)(__autoreleasing const id *)csip;
+}
+
+void test_functional_cast(__strong id *sip, __weak id *wip,
+ __autoreleasing id *aip) {
+ // Functional casts aren't allowed to change Objective-C ownership
+ // qualifiers (beyond what the normal implicit conversion allows).
+
+ typedef __strong id *strong_id_pointer;
+ typedef __weak id *weak_id_pointer;
+ typedef __autoreleasing id *autoreleasing_id_pointer;
+
+ typedef const __strong id *const_strong_id_pointer;
+ typedef const __weak id *const_weak_id_pointer;
+ typedef const __autoreleasing id *const_autoreleasing_id_pointer;
+
+ (void)strong_id_pointer(wip); // expected-error{{functional-style cast from '__weak id *' to 'strong_id_pointer' (aka '__strong id *') casts away qualifiers}}
+ (void)weak_id_pointer(sip); // expected-error{{functional-style cast from '__strong id *' to 'weak_id_pointer' (aka '__weak id *') casts away qualifiers}}
+ (void)autoreleasing_id_pointer(sip); // expected-error{{functional-style cast from '__strong id *' to 'autoreleasing_id_pointer' (aka '__autoreleasing id *') casts away qualifiers}}
+ (void)autoreleasing_id_pointer(wip); // expected-error{{functional-style cast from '__weak id *' to 'autoreleasing_id_pointer' (aka '__autoreleasing id *') casts away qualifiers}}
+ (void)const_strong_id_pointer(wip); // expected-error{{functional-style cast from '__weak id *' to 'const_strong_id_pointer' (aka 'const __strong id *') casts away qualifiers}}
+ (void)const_weak_id_pointer(sip); // expected-error{{functional-style cast from '__strong id *' to 'const_weak_id_pointer' (aka 'const __weak id *') casts away qualifiers}}
+ (void)const_autoreleasing_id_pointer(sip);
+ (void)const_autoreleasing_id_pointer(aip);
+ (void)const_autoreleasing_id_pointer(wip); // expected-error{{functional-style cast from '__weak id *' to 'const_autoreleasing_id_pointer' (aka 'const __autoreleasing id *') casts away qualifiers}}
+}
+
+void test_unsafe_unretained(__strong id *sip, __weak id *wip,
+ __autoreleasing id *aip,
+ __unsafe_unretained id *uip,
+ const __unsafe_unretained id *cuip) {
+ uip = sip; // expected-error{{assigning to '__unsafe_unretained id *' from incompatible type '__strong id *'}}
+ uip = wip; // expected-error{{assigning to '__unsafe_unretained id *' from incompatible type '__weak id *'}}
+ uip = aip; // expected-error{{assigning to '__unsafe_unretained id *' from incompatible type '__autoreleasing id *'}}
+
+ cuip = sip;
+ cuip = wip; // expected-error{{assigning to '__unsafe_unretained id const *' from incompatible type '__weak id *'}}
+ cuip = aip;
+}
+
+void to_void(__strong id *sip, __weak id *wip,
+ __autoreleasing id *aip,
+ __unsafe_unretained id *uip) {
+ void *vp1 = sip;
+ void *vp2 = wip;
+ void *vp3 = aip;
+ void *vp4 = uip;
+ (void)(void*)sip;
+ (void)(void*)wip;
+ (void)(void*)aip;
+ (void)(void*)uip;
+ (void)static_cast<void*>(sip);
+ (void)static_cast<void*>(wip);
+ (void)static_cast<void*>(aip);
+ (void)static_cast<void*>(uip);
+ (void)reinterpret_cast<void*>(sip);
+ (void)reinterpret_cast<void*>(wip);
+ (void)reinterpret_cast<void*>(aip);
+ (void)reinterpret_cast<void*>(uip);
+
+ (void)(void*)&sip;
+ (void)(void*)&wip;
+ (void)(void*)&aip;
+ (void)(void*)&uip;
+ (void)static_cast<void*>(&sip);
+ (void)static_cast<void*>(&wip);
+ (void)static_cast<void*>(&aip);
+ (void)static_cast<void*>(&uip);
+ (void)reinterpret_cast<void*>(&sip);
+ (void)reinterpret_cast<void*>(&wip);
+ (void)reinterpret_cast<void*>(&aip);
+ (void)reinterpret_cast<void*>(&uip);
+}
+
+void from_void(void *vp) {
+ __strong id *sip = (__strong id *)vp;
+ __weak id *wip = (__weak id *)vp;
+ __autoreleasing id *aip = (__autoreleasing id *)vp;
+ __unsafe_unretained id *uip = (__unsafe_unretained id *)vp;
+ __strong id *sip2 = static_cast<__strong id *>(vp);
+ __weak id *wip2 = static_cast<__weak id *>(vp);
+ __autoreleasing id *aip2 = static_cast<__autoreleasing id *>(vp);
+ __unsafe_unretained id *uip2 = static_cast<__unsafe_unretained id *>(vp);
+ __strong id *sip3 = reinterpret_cast<__strong id *>(vp);
+ __weak id *wip3 = reinterpret_cast<__weak id *>(vp);
+ __autoreleasing id *aip3 = reinterpret_cast<__autoreleasing id *>(vp);
+ __unsafe_unretained id *uip3 = reinterpret_cast<__unsafe_unretained id *>(vp);
+
+ __strong id **sipp = (__strong id **)vp;
+ __weak id **wipp = (__weak id **)vp;
+ __autoreleasing id **aipp = (__autoreleasing id **)vp;
+ __unsafe_unretained id **uipp = (__unsafe_unretained id **)vp;
+
+ sip = vp; // expected-error{{assigning to '__strong id *' from incompatible type 'void *'}}
+ wip = vp; // expected-error{{assigning to '__weak id *' from incompatible type 'void *'}}
+ aip = vp; // expected-error{{assigning to '__autoreleasing id *' from incompatible type 'void *'}}
+ uip = vp; // expected-error{{assigning to '__unsafe_unretained id *' from incompatible type 'void *'}}
+}
+
+typedef void (^Block)();
+typedef void (^Block_strong)() __strong;
+typedef void (^Block_autoreleasing)() __autoreleasing;
+
+@class NSString;
+
+void ownership_transfer_in_cast(void *vp, Block *pblk) {
+ __strong NSString **sip2 = static_cast<NSString **>(static_cast<__strong id *>(vp));
+ __strong NSString **&si2pref = static_cast<NSString **&>(sip2);
+ __weak NSString **wip2 = static_cast<NSString **>(static_cast<__weak id *>(vp));
+ __autoreleasing id *aip2 = static_cast<id *>(static_cast<__autoreleasing id *>(vp));
+ __unsafe_unretained id *uip2 = static_cast<id *>(static_cast<__unsafe_unretained id *>(vp));
+ __strong id *sip3 = reinterpret_cast<id *>(reinterpret_cast<__strong id *>(vp));
+ __weak id *wip3 = reinterpret_cast<id *>(reinterpret_cast<__weak id *>(vp));
+ __autoreleasing id *aip3 = reinterpret_cast<id *>(reinterpret_cast<__autoreleasing id *>(vp));
+ __unsafe_unretained id *uip3 = reinterpret_cast<id *>(reinterpret_cast<__unsafe_unretained id *>(vp));
+
+ Block_strong blk_strong1;
+ Block_strong blk_strong2 = static_cast<Block>(blk_strong1);
+ Block_autoreleasing *blk_auto = static_cast<Block*>(pblk);
+}
+
+// Make sure we don't crash.
+void writeback_test(NSString & &) {} // expected-error {{type name declared as a reference to a reference}}
diff --git a/test/SemaObjCXX/arc-type-traits.mm b/test/SemaObjCXX/arc-type-traits.mm
new file mode 100644
index 000000000000..f50904b03c73
--- /dev/null
+++ b/test/SemaObjCXX/arc-type-traits.mm
@@ -0,0 +1,90 @@
+// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -fobjc-nonfragile-abi -fobjc-runtime-has-weak -verify %s
+
+// Check the results of the various type-trait query functions on
+// lifetime-qualified types in ARC.
+
+#define JOIN3(X,Y) X ## Y
+#define JOIN2(X,Y) JOIN3(X,Y)
+#define JOIN(X,Y) JOIN2(X,Y)
+
+#define TRAIT_IS_TRUE(Trait, Type) char JOIN2(Trait,__LINE__)[Trait(Type)? 1 : -1]
+#define TRAIT_IS_FALSE(Trait, Type) char JOIN2(Trait,__LINE__)[Trait(Type)? -1 : 1]
+
+// __has_nothrow_assign
+TRAIT_IS_TRUE(__has_nothrow_assign, __strong id);
+TRAIT_IS_TRUE(__has_nothrow_assign, __weak id);
+TRAIT_IS_TRUE(__has_nothrow_assign, __autoreleasing id);
+TRAIT_IS_TRUE(__has_nothrow_assign, __unsafe_unretained id);
+
+// __has_nothrow_copy
+TRAIT_IS_TRUE(__has_nothrow_copy, __strong id);
+TRAIT_IS_TRUE(__has_nothrow_copy, __weak id);
+TRAIT_IS_TRUE(__has_nothrow_copy, __autoreleasing id);
+TRAIT_IS_TRUE(__has_nothrow_copy, __unsafe_unretained id);
+
+// __has_nothrow_constructor
+TRAIT_IS_TRUE(__has_nothrow_constructor, __strong id);
+TRAIT_IS_TRUE(__has_nothrow_constructor, __weak id);
+TRAIT_IS_TRUE(__has_nothrow_constructor, __autoreleasing id);
+TRAIT_IS_TRUE(__has_nothrow_constructor, __unsafe_unretained id);
+
+// __has_trivial_assign
+TRAIT_IS_FALSE(__has_trivial_assign, __strong id);
+TRAIT_IS_FALSE(__has_trivial_assign, __weak id);
+TRAIT_IS_FALSE(__has_trivial_assign, __autoreleasing id);
+TRAIT_IS_TRUE(__has_trivial_assign, __unsafe_unretained id);
+
+// __has_trivial_copy
+TRAIT_IS_FALSE(__has_trivial_copy, __strong id);
+TRAIT_IS_FALSE(__has_trivial_copy, __weak id);
+TRAIT_IS_FALSE(__has_trivial_copy, __autoreleasing id);
+TRAIT_IS_TRUE(__has_trivial_copy, __unsafe_unretained id);
+
+// __has_trivial_constructor
+TRAIT_IS_FALSE(__has_trivial_constructor, __strong id);
+TRAIT_IS_FALSE(__has_trivial_constructor, __weak id);
+TRAIT_IS_FALSE(__has_trivial_constructor, __autoreleasing id);
+TRAIT_IS_TRUE(__has_trivial_constructor, __unsafe_unretained id);
+
+// __has_trivial_destructor
+TRAIT_IS_FALSE(__has_trivial_destructor, __strong id);
+TRAIT_IS_FALSE(__has_trivial_destructor, __weak id);
+TRAIT_IS_TRUE(__has_trivial_destructor, __autoreleasing id);
+TRAIT_IS_TRUE(__has_trivial_destructor, __unsafe_unretained id);
+
+// __is_literal
+TRAIT_IS_FALSE(__is_literal, __strong id);
+TRAIT_IS_FALSE(__is_literal, __weak id);
+TRAIT_IS_FALSE(__is_literal, __autoreleasing id);
+TRAIT_IS_FALSE(__is_literal, __unsafe_unretained id);
+
+// __is_literal_type
+TRAIT_IS_FALSE(__is_literal_type, __strong id);
+TRAIT_IS_FALSE(__is_literal_type, __weak id);
+TRAIT_IS_FALSE(__is_literal_type, __autoreleasing id);
+TRAIT_IS_FALSE(__is_literal_type, __unsafe_unretained id);
+
+// __is_pod
+TRAIT_IS_FALSE(__is_pod, __strong id);
+TRAIT_IS_FALSE(__is_pod, __weak id);
+TRAIT_IS_FALSE(__is_pod, __autoreleasing id);
+TRAIT_IS_TRUE(__is_pod, __unsafe_unretained id);
+
+// __is_trivial
+TRAIT_IS_FALSE(__is_trivial, __strong id);
+TRAIT_IS_FALSE(__is_trivial, __weak id);
+TRAIT_IS_FALSE(__is_trivial, __autoreleasing id);
+TRAIT_IS_TRUE(__is_trivial, __unsafe_unretained id);
+
+// __is_scalar
+TRAIT_IS_FALSE(__is_scalar, __strong id);
+TRAIT_IS_FALSE(__is_scalar, __weak id);
+TRAIT_IS_FALSE(__is_scalar, __autoreleasing id);
+TRAIT_IS_TRUE(__is_scalar, __unsafe_unretained id);
+
+// __is_standard_layout
+TRAIT_IS_TRUE(__is_standard_layout, __strong id);
+TRAIT_IS_TRUE(__is_standard_layout, __weak id);
+TRAIT_IS_TRUE(__is_standard_layout, __autoreleasing id);
+TRAIT_IS_TRUE(__is_standard_layout, __unsafe_unretained id);
+
diff --git a/test/SemaObjCXX/arc-unavailable-for-weakref.mm b/test/SemaObjCXX/arc-unavailable-for-weakref.mm
new file mode 100644
index 000000000000..a7b357006843
--- /dev/null
+++ b/test/SemaObjCXX/arc-unavailable-for-weakref.mm
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -verify %s
+// rdar://9693477
+
+__attribute__((objc_arc_weak_reference_unavailable))
+@interface NSOptOut1072 // expected-note {{class is declared here}}
+@end
+
+@interface sub : NSOptOut1072 @end // expected-note 2 {{class is declared here}}
+
+int main() {
+ __weak sub *w2; // expected-error {{class is incompatible with __weak references}}
+
+ __weak NSOptOut1072 *ns1; // expected-error {{class is incompatible with __weak references}}
+
+ id obj;
+
+ ns1 = (__weak sub *)obj; // expected-error {{assignment of a weak-unavailable object to a __weak object}} \
+ // expected-error {{class is incompatible with __weak references}}
+}
+
+// rdar://9732636
+__attribute__((objc_arc_weak_reference_unavailable))
+@interface NOWEAK
++ (id) new;
+@end
+
+NOWEAK * Test1() {
+ NOWEAK * strong1 = [NOWEAK new];
+ __weak id weak1;
+ weak1 = strong1; // expected-error {{assignment of a weak-unavailable object to a __weak object}}
+
+ __weak id weak2 = strong1; // expected-error {{assignment of a weak-unavailable object to a __weak object}}
+ return (__weak id)strong1; // expected-error {{cast of weak-unavailable object of type 'NOWEAK *' to a __weak object of type '__weak id'}}
+}
+
+@protocol P @end
+@protocol P1 @end
+
+NOWEAK<P, P1> * Test2() {
+ NOWEAK<P, P1> * strong1 = 0;
+ __weak id<P> weak1;
+ weak1 = strong1; // expected-error {{assignment of a weak-unavailable object to a __weak object}}
+
+ __weak id<P> weak2 = strong1; // expected-error {{assignment of a weak-unavailable object to a __weak object}}
+ return (__weak id<P, P1>)strong1; // expected-error {{cast of weak-unavailable object of type 'NOWEAK<P,P1> *' to a __weak object of type '__weak id<P,P1>'}}
+}
+
diff --git a/test/SemaObjCXX/exceptions-fragile.mm b/test/SemaObjCXX/exceptions-fragile.mm
index d1e7077089e2..71e259aa6bba 100644
--- a/test/SemaObjCXX/exceptions-fragile.mm
+++ b/test/SemaObjCXX/exceptions-fragile.mm
@@ -6,7 +6,7 @@ void opaque();
namespace test0 {
void test() {
try {
- } catch (NSException *e) { // expected-error {{can't catch Objective C exceptions in C++ in the non-unified exception model}}
+ } catch (NSException *e) { // expected-warning {{can not catch an exception thrown with @throw in C++ in the non-unified exception model}}
}
}
}
diff --git a/test/SemaObjCXX/gc-attributes.mm b/test/SemaObjCXX/gc-attributes.mm
index 70a93b2e33d1..4549683bb2e0 100644
--- a/test/SemaObjCXX/gc-attributes.mm
+++ b/test/SemaObjCXX/gc-attributes.mm
@@ -3,7 +3,7 @@
@interface A
@end
-void f0(__strong A**); // expected-note{{candidate function not viable: 1st argument ('A *__weak *') has __weak lifetime, but parameter has __strong lifetime}}
+void f0(__strong A**); // expected-note{{candidate function not viable: 1st argument ('A *__weak *') has __weak ownership, but parameter has __strong ownership}}
void test_f0() {
A *a;
@@ -12,7 +12,7 @@ void test_f0() {
f0(&a2); // expected-error{{no matching function}}
}
-void f1(__weak A**); // expected-note{{candidate function not viable: 1st argument ('A *__strong *') has __strong lifetime, but parameter has __weak lifetime}}
+void f1(__weak A**); // expected-note{{candidate function not viable: 1st argument ('A *__strong *') has __strong ownership, but parameter has __weak ownership}}
void test_f1() {
A *a;
diff --git a/test/SemaObjCXX/null_objc_pointer.mm b/test/SemaObjCXX/null_objc_pointer.mm
new file mode 100644
index 000000000000..0da9e50f5a1c
--- /dev/null
+++ b/test/SemaObjCXX/null_objc_pointer.mm
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wnull-arithmetic %s
+#define NULL __null
+
+@interface X
+@end
+
+void f() {
+ bool b;
+ X *d;
+ b = d < NULL || NULL < d || d > NULL || NULL > d;
+ b = d <= NULL || NULL <= d || d >= NULL || NULL >= d;
+ b = d == NULL || NULL == d || d != NULL || NULL != d;
+}
diff --git a/test/SemaObjCXX/nullptr.mm b/test/SemaObjCXX/nullptr.mm
index 4cd5669ef5ae..4a9d1a07de9d 100644
--- a/test/SemaObjCXX/nullptr.mm
+++ b/test/SemaObjCXX/nullptr.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++0x -fblocks -fsyntax-only -verify %s
@interface A
@end
@@ -11,3 +11,6 @@ void comparisons(A *a) {
void assignment(A *a) {
a = nullptr;
}
+
+int PR10145a = (void(^)())0 == nullptr;
+int PR10145b = nullptr == (void(^)())0;
diff --git a/test/SemaObjCXX/property-type-mismatch.mm b/test/SemaObjCXX/property-type-mismatch.mm
new file mode 100644
index 000000000000..059793cf5ceb
--- /dev/null
+++ b/test/SemaObjCXX/property-type-mismatch.mm
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// rdar://9740328
+
+@protocol P1;
+
+@interface NSObject
+@end
+
+@interface A : NSObject
+@property (assign) NSObject<P1> *prop;
+@end
+
+@protocol P2 <P1>
+@end
+
+@interface B : A
+@property (assign) NSObject<P2> *prop;
+@end
+
diff --git a/test/SemaObjCXX/related-result-type-inference.mm b/test/SemaObjCXX/related-result-type-inference.mm
index c3cab05194fc..675e6acbda14 100644
--- a/test/SemaObjCXX/related-result-type-inference.mm
+++ b/test/SemaObjCXX/related-result-type-inference.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-infer-related-result-type -verify %s
+// RUN: %clang_cc1 -verify %s
@interface Unrelated
@end
diff --git a/test/SemaOpenCL/vector_literals_invalid.cl b/test/SemaOpenCL/vector_literals_invalid.cl
new file mode 100644
index 000000000000..957680f44ffe
--- /dev/null
+++ b/test/SemaOpenCL/vector_literals_invalid.cl
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -verify %s
+
+typedef __attribute__(( ext_vector_type(4) )) float float4;
+typedef __attribute__(( ext_vector_type(4) )) int int4;
+typedef __attribute__(( ext_vector_type(8) )) int int8;
+
+void vector_literals_invalid()
+{
+ int4 a = (int4)(1,2,3); // expected-error{{too few elements}}
+ int4 b = (int4)(1,2,3,4,5); // expected-error{{excess elements in vector}}
+ ((float4)(1.0f))++; // expected-error{{expression is not assignable}}
+ int8 d = (int8)(a,(float4)(1)); // expected-error{{initializing 'int' with an expression of incompatible type 'float4'}}
+}
diff --git a/test/SemaTemplate/class-template-decl.cpp b/test/SemaTemplate/class-template-decl.cpp
index e7722123f9c2..2e84e93ead97 100644
--- a/test/SemaTemplate/class-template-decl.cpp
+++ b/test/SemaTemplate/class-template-decl.cpp
@@ -50,7 +50,7 @@ void f() {
template<typename T> class X; // expected-error{{expression}}
}
-template<typename T> class X1 { } var; // expected-error{{declared as a template}}
+template<typename T> class X1 var; // expected-error{{declared as a template}}
namespace M {
}
diff --git a/test/SemaTemplate/deduction.cpp b/test/SemaTemplate/deduction.cpp
index 15c061c26198..aecb5ee7c8b3 100644
--- a/test/SemaTemplate/deduction.cpp
+++ b/test/SemaTemplate/deduction.cpp
@@ -150,3 +150,15 @@ namespace test3 {
}
};
}
+
+// Verify that we can deduce enum-typed arguments correctly.
+namespace test14 {
+ enum E { E0, E1 };
+ template <E> struct A {};
+ template <E e> void foo(const A<e> &a) {}
+
+ void test() {
+ A<E0> a;
+ foo(a);
+ }
+}
diff --git a/test/SemaTemplate/default-arguments.cpp b/test/SemaTemplate/default-arguments.cpp
index 9ea0fc2e4d52..6391369aa5c4 100644
--- a/test/SemaTemplate/default-arguments.cpp
+++ b/test/SemaTemplate/default-arguments.cpp
@@ -121,3 +121,18 @@ X6<long, X5b> x6c;
template<template<class> class X = B<int> > struct X7; // expected-error{{must be a class template}}
+
+namespace PR9643 {
+ template<typename T> class allocator {};
+ template<typename T, typename U = allocator<T> > class vector {};
+
+ template<template<typename U, typename = allocator<U> > class container,
+ typename DT>
+ container<DT> initializer(const DT& d) {
+ return container<DT>();
+ }
+
+ void f() {
+ vector<int, allocator<int> > v = initializer<vector>(5);
+ }
+}
diff --git a/test/SemaTemplate/dependent-names-no-std.cpp b/test/SemaTemplate/dependent-names-no-std.cpp
index e9ac99faf65b..2fb9d9909f75 100644
--- a/test/SemaTemplate/dependent-names-no-std.cpp
+++ b/test/SemaTemplate/dependent-names-no-std.cpp
@@ -11,7 +11,7 @@ namespace PR10053 {
template<typename T> struct A {
T t;
A() {
- f(t); // expected-error {{call to function 'f' that is neither visible in the template definition nor found by argument dependent lookup}}
+ f(t); // expected-error {{call to function 'f' that is neither visible in the template definition nor found by argument-dependent lookup}}
}
};
diff --git a/test/SemaTemplate/dependent-names.cpp b/test/SemaTemplate/dependent-names.cpp
index 2a50df5b7f14..7bab5d18d1ad 100644
--- a/test/SemaTemplate/dependent-names.cpp
+++ b/test/SemaTemplate/dependent-names.cpp
@@ -148,7 +148,7 @@ namespace PR10053 {
template<typename T> struct A {
T t;
A() {
- f(t); // expected-error {{call to function 'f' that is neither visible in the template definition nor found by argument dependent lookup}}
+ f(t); // expected-error {{call to function 'f' that is neither visible in the template definition nor found by argument-dependent lookup}}
}
};
@@ -160,7 +160,7 @@ namespace PR10053 {
namespace N {
namespace M {
template<typename T> int g(T t) {
- f(t); // expected-error {{call to function 'f' that is neither visible in the template definition nor found by argument dependent lookup}}
+ f(t); // expected-error {{call to function 'f' that is neither visible in the template definition nor found by argument-dependent lookup}}
};
}
@@ -187,7 +187,7 @@ namespace PR10053 {
// Example from www/compatibility.html
namespace my_file {
template <typename T> T Squared(T x) {
- return Multiply(x, x); // expected-error {{neither visible in the template definition nor found by argument dependent lookup}}
+ return Multiply(x, x); // expected-error {{neither visible in the template definition nor found by argument-dependent lookup}}
}
int Multiply(int x, int y) { // expected-note {{should be declared prior to the call site}}
@@ -203,7 +203,7 @@ namespace PR10053 {
namespace my_file2 {
template<typename T>
void Dump(const T& value) {
- std::cout << value << "\n"; // expected-error {{neither visible in the template definition nor found by argument dependent lookup}}
+ std::cout << value << "\n"; // expected-error {{neither visible in the template definition nor found by argument-dependent lookup}}
}
namespace ns {
@@ -222,7 +222,7 @@ namespace PR10053 {
namespace my_file2_a {
template<typename T>
void Dump(const T &value) {
- print(std::cout, value); // expected-error 4{{neither visible in the template definition nor found by argument dependent lookup}}
+ print(std::cout, value); // expected-error 4{{neither visible in the template definition nor found by argument-dependent lookup}}
}
namespace ns {
@@ -248,7 +248,7 @@ namespace PR10053 {
namespace unary {
template<typename T>
T Negate(const T& value) {
- return !value; // expected-error {{call to function 'operator!' that is neither visible in the template definition nor found by argument dependent lookup}}
+ return !value; // expected-error {{call to function 'operator!' that is neither visible in the template definition nor found by argument-dependent lookup}}
}
namespace ns {
@@ -262,3 +262,33 @@ namespace PR10053 {
}
}
}
+
+namespace PR10187 {
+ namespace A {
+ template<typename T>
+ struct S {
+ void f() {
+ for (auto &a : e)
+ __range(a); // expected-error {{undeclared identifier '__range'}}
+ }
+ int e[10];
+ };
+ void g() {
+ S<int>().f(); // expected-note {{here}}
+ }
+ }
+
+ namespace B {
+ template<typename T> void g(); // expected-note {{not viable}}
+ template<typename T> void f() {
+ g<int>(T()); // expected-error {{no matching function}}
+ }
+
+ namespace {
+ struct S {};
+ }
+ void g(S);
+
+ template void f<S>(); // expected-note {{here}}
+ }
+}
diff --git a/test/SemaTemplate/ext-vector-type.cpp b/test/SemaTemplate/ext-vector-type.cpp
index 7334e88e9267..f968c13f1023 100644
--- a/test/SemaTemplate/ext-vector-type.cpp
+++ b/test/SemaTemplate/ext-vector-type.cpp
@@ -58,3 +58,37 @@ int test_make6() {
y.x = -1;
y.w = -1; // expected-error{{vector component access exceeds type}}
}
+
+namespace Deduction {
+ template<typename T> struct X0;
+
+ template<typename T, unsigned N>
+ struct X0<T __attribute__((ext_vector_type(N)))> {
+ static const unsigned value = 0;
+ };
+
+ template<typename T>
+ struct X0<T __attribute__((ext_vector_type(4)))> {
+ static const unsigned value = 1;
+ };
+
+ template<unsigned N>
+ struct X0<float __attribute__((ext_vector_type(N)))> {
+ static const unsigned value = 2;
+ };
+
+ template<>
+ struct X0<float __attribute__((ext_vector_type(4)))> {
+ static const unsigned value = 3;
+ };
+
+ typedef int __attribute__((ext_vector_type(2))) int2;
+ typedef int __attribute__((ext_vector_type(4))) int4;
+ typedef float __attribute__((ext_vector_type(2))) float2;
+ typedef float __attribute__((ext_vector_type(4))) float4;
+
+ int array0[X0<int2>::value == 0? 1 : -1];
+ int array1[X0<int4>::value == 1? 1 : -1];
+ int array2[X0<float2>::value == 2? 1 : -1];
+ int array3[X0<float4>::value == 3? 1 : -1];
+}
diff --git a/test/SemaTemplate/instantiate-call.cpp b/test/SemaTemplate/instantiate-call.cpp
index a0e48c8dec77..da1eb49eb89e 100644
--- a/test/SemaTemplate/instantiate-call.cpp
+++ b/test/SemaTemplate/instantiate-call.cpp
@@ -25,7 +25,7 @@ namespace N3 {
struct call_f0 {
void test_f0(T t) {
Result &result = f0(t); // expected-error {{undeclared identifier}} \
- expected-error {{neither visible in the template definition nor found by argument dependent lookup}}
+ expected-error {{neither visible in the template definition nor found by argument-dependent lookup}}
}
};
}
diff --git a/test/SemaTemplate/instantiate-function-2.cpp b/test/SemaTemplate/instantiate-function-2.cpp
index ebc0ef3a9f96..087ede2b89cb 100644
--- a/test/SemaTemplate/instantiate-function-2.cpp
+++ b/test/SemaTemplate/instantiate-function-2.cpp
@@ -31,3 +31,36 @@ namespace UsedAttr {
foo<int>(); // expected-note{{instantiation of}}
}
}
+
+namespace PR9654 {
+ typedef void ftype(int);
+
+ template<typename T>
+ ftype f;
+
+ void g() {
+ f<int>(0);
+ }
+}
+
+namespace AliasTagDef {
+ template<typename T>
+ T f() {
+ using S = struct { // expected-warning {{C++0x}}
+ T g() {
+ return T();
+ }
+ };
+ return S().g();
+ }
+
+ int n = f<int>();
+}
+
+namespace PR10273 {
+ template<typename T> void (f)(T t) {}
+
+ void g() {
+ (f)(17);
+ }
+}
diff --git a/test/SemaTemplate/instantiate-member-class.cpp b/test/SemaTemplate/instantiate-member-class.cpp
index 74c2609dcd0f..1028b45cc0e1 100644
--- a/test/SemaTemplate/instantiate-member-class.cpp
+++ b/test/SemaTemplate/instantiate-member-class.cpp
@@ -104,3 +104,17 @@ namespace test2 {
};
template class C<int>;
}
+
+namespace AliasTagDef {
+ template<typename T>
+ struct F {
+ using S = struct U { // expected-warning {{C++0x}}
+ T g() {
+ return T();
+ }
+ };
+ };
+
+ int m = F<int>::S().g();
+ int n = F<int>::U().g();
+}
diff --git a/test/SemaTemplate/instantiate-try-catch.cpp b/test/SemaTemplate/instantiate-try-catch.cpp
index 1c6c26f2586e..f4ce0e173146 100644
--- a/test/SemaTemplate/instantiate-try-catch.cpp
+++ b/test/SemaTemplate/instantiate-try-catch.cpp
@@ -12,3 +12,20 @@ template struct TryCatch0<int&>; // okay
template struct TryCatch0<int&&>; // expected-note{{instantiation}}
template struct TryCatch0<int>; // expected-note{{instantiation}}
+
+namespace PR10232 {
+ template <typename T>
+ class Templated {
+ struct Exception {
+ private:
+ Exception(const Exception&); // expected-note{{declared private here}}
+ };
+ void exception() {
+ try {
+ } catch(Exception e) { // expected-error{{calling a private constructor of class 'PR10232::Templated<int>::Exception'}}
+ }
+ }
+ };
+
+ template class Templated<int>; // expected-note{{in instantiation of member function 'PR10232::Templated<int>::exception' requested here}}
+}
diff --git a/test/SemaTemplate/member-inclass-init-value-dependent.cpp b/test/SemaTemplate/member-inclass-init-value-dependent.cpp
new file mode 100644
index 000000000000..d1ae4f2ded5f
--- /dev/null
+++ b/test/SemaTemplate/member-inclass-init-value-dependent.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -emit-llvm-only %s
+// PR10290
+
+template<int Flags> struct foo {
+ int value = Flags && 0;
+};
+
+void test() {
+ foo<4> bar;
+}
+
diff --git a/test/SemaTemplate/unresolved-construct.cpp b/test/SemaTemplate/unresolved-construct.cpp
new file mode 100644
index 000000000000..0d1ba17a0179
--- /dev/null
+++ b/test/SemaTemplate/unresolved-construct.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+class A
+{
+public:
+ A() {}
+
+ template <class _F>
+ explicit A(_F&& __f);
+
+ A(A&&) {}
+ A& operator=(A&&) {return *this;}
+};
+
+template <class T>
+void f(T t)
+{
+ A a;
+ a = f(t);
+}
diff --git a/test/Unit/lit.cfg b/test/Unit/lit.cfg
index 794234ce5575..8f27781523f0 100644
--- a/test/Unit/lit.cfg
+++ b/test/Unit/lit.cfg
@@ -30,14 +30,6 @@ if 'TEMP' in os.environ:
###
-# If necessary, point the dynamic loader at libLLVM.so.
-if config.enable_shared:
- shlibpath = config.environment.get(config.shlibpath_var,'')
- if shlibpath:
- shlibpath = os.pathsep + shlibpath
- shlibpath = config.shlibdir + shlibpath
- config.environment[config.shlibpath_var] = shlibpath
-
# Check that the object root is known.
if config.test_exec_root is None:
# Otherwise, we haven't loaded the site specific configuration (the user is
@@ -71,7 +63,7 @@ if config.test_exec_root is None:
# Validate that we got a tree which points to here, using the standard
# tools/clang layout.
- this_src_root = os.path.dirname(config.test_source_root)
+ this_src_root = os.path.join(os.path.dirname(__file__),'..','..')
if os.path.realpath(clang_src_root) != os.path.realpath(this_src_root):
lit.fatal('No site specific configuration available!')
@@ -84,3 +76,11 @@ if config.test_exec_root is None:
lit.note('using out-of-tree build at %r' % clang_obj_root)
lit.load_config(config, site_cfg)
raise SystemExit
+
+# If necessary, point the dynamic loader at libLLVM.so.
+if config.enable_shared:
+ shlibpath = config.environment.get(config.shlibpath_var,'')
+ if shlibpath:
+ shlibpath = os.pathsep + shlibpath
+ shlibpath = config.shlibdir + shlibpath
+ config.environment[config.shlibpath_var] = shlibpath
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index ae33b782d49d..aff437fd467a 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -1,3 +1,5 @@
add_subdirectory(libclang)
add_subdirectory(c-index-test)
+add_subdirectory(arcmt-test)
+add_subdirectory(c-arcmt-test)
add_subdirectory(driver)
diff --git a/tools/Makefile b/tools/Makefile
index 000293f09c9f..bfd2a641ec1e 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -8,12 +8,12 @@
##===----------------------------------------------------------------------===##
CLANG_LEVEL := ..
-DIRS := driver libclang c-index-test
+DIRS := driver libclang c-index-test arcmt-test c-arcmt-test
include $(CLANG_LEVEL)/../../Makefile.config
ifeq ($(OS), $(filter $(OS), Minix))
-DIRS := $(filter-out libclang c-index-test, $(DIRS))
+DIRS := $(filter-out libclang c-index-test, arcmt-test, $(DIRS))
endif
include $(CLANG_LEVEL)/Makefile
diff --git a/tools/arcmt-test/CMakeLists.txt b/tools/arcmt-test/CMakeLists.txt
new file mode 100644
index 000000000000..9227f8ee63c7
--- /dev/null
+++ b/tools/arcmt-test/CMakeLists.txt
@@ -0,0 +1,13 @@
+set(LLVM_USED_LIBS
+ clangARCMigrate
+ clangRewrite
+ )
+
+set( LLVM_LINK_COMPONENTS
+ support
+ mc
+ )
+
+add_clang_executable(arcmt-test
+ arcmt-test.cpp
+ )
diff --git a/tools/arcmt-test/Makefile b/tools/arcmt-test/Makefile
new file mode 100644
index 000000000000..c143e27f33e2
--- /dev/null
+++ b/tools/arcmt-test/Makefile
@@ -0,0 +1,24 @@
+##===- tools/arcmt-test/Makefile ---------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+CLANG_LEVEL := ../..
+
+TOOLNAME = arcmt-test
+
+# No plugins, optimize startup time.
+TOOL_NO_EXPORTS = 1
+
+# Don't install this. It is used for tests.
+NO_INSTALL = 1
+
+LINK_COMPONENTS := support mc
+USEDLIBS = clangIndex.a clangARCMigrate.a clangRewrite.a \
+ clangFrontend.a clangDriver.a clangSerialization.a clangParse.a \
+ clangSema.a clangAnalysis.a clangAST.a clangLex.a clangBasic.a
+
+include $(CLANG_LEVEL)/Makefile
diff --git a/tools/arcmt-test/arcmt-test.cpp b/tools/arcmt-test/arcmt-test.cpp
new file mode 100644
index 000000000000..eb0f56943f96
--- /dev/null
+++ b/tools/arcmt-test/arcmt-test.cpp
@@ -0,0 +1,374 @@
+//===-- arcmt-test.cpp - ARC Migration Tool testbed -----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/ARCMigrate/ARCMT.h"
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Frontend/VerifyDiagnosticsClient.h"
+#include "clang/Frontend/Utils.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/system_error.h"
+
+using namespace clang;
+using namespace arcmt;
+
+static llvm::cl::opt<bool>
+CheckOnly("check-only",
+ llvm::cl::desc("Just check for issues that need to be handled manually"));
+
+//static llvm::cl::opt<bool>
+//TestResultForARC("test-result",
+//llvm::cl::desc("Test the result of transformations by parsing it in ARC mode"));
+
+static llvm::cl::opt<bool>
+OutputTransformations("output-transformations",
+ llvm::cl::desc("Print the source transformations"));
+
+static llvm::cl::opt<bool>
+VerifyDiags("verify",llvm::cl::desc("Verify emitted diagnostics and warnings"));
+
+static llvm::cl::opt<bool>
+VerboseOpt("v", llvm::cl::desc("Enable verbose output"));
+
+static llvm::cl::opt<bool>
+VerifyTransformedFiles("verify-transformed-files",
+llvm::cl::desc("Read pairs of file mappings (typically the output of "
+ "c-arcmt-test) and compare their contents with the filenames "
+ "provided in command-line"));
+
+static llvm::cl::opt<std::string>
+RemappingsFile("remappings-file",
+ llvm::cl::desc("Pairs of file mappings (typically the output of "
+ "c-arcmt-test)"));
+
+static llvm::cl::list<std::string>
+ResultFiles(llvm::cl::Positional, llvm::cl::desc("<filename>..."));
+
+static llvm::cl::extrahelp extraHelp(
+ "\nusage with compiler args: arcmt-test [options] --args [compiler flags]\n");
+
+// This function isn't referenced outside its translation unit, but it
+// can't use the "static" keyword because its address is used for
+// GetMainExecutable (since some platforms don't support taking the
+// address of main, and some platforms can't implement GetMainExecutable
+// without being given the address of a function in the main executable).
+llvm::sys::Path GetExecutablePath(const char *Argv0) {
+ // This just needs to be some symbol in the binary; C++ doesn't
+ // allow taking the address of ::main however.
+ void *MainAddr = (void*) (intptr_t) GetExecutablePath;
+ return llvm::sys::Path::GetMainExecutable(Argv0, MainAddr);
+}
+
+static void printSourceLocation(SourceLocation loc, ASTContext &Ctx,
+ llvm::raw_ostream &OS);
+static void printSourceRange(CharSourceRange range, ASTContext &Ctx,
+ llvm::raw_ostream &OS);
+
+namespace {
+
+class PrintTransforms : public MigrationProcess::RewriteListener {
+ ASTContext *Ctx;
+ llvm::raw_ostream &OS;
+
+public:
+ PrintTransforms(llvm::raw_ostream &OS)
+ : Ctx(0), OS(OS) { }
+
+ virtual void start(ASTContext &ctx) { Ctx = &ctx; }
+ virtual void finish() { Ctx = 0; }
+
+ virtual void insert(SourceLocation loc, llvm::StringRef text) {
+ assert(Ctx);
+ OS << "Insert: ";
+ printSourceLocation(loc, *Ctx, OS);
+ OS << " \"" << text << "\"\n";
+ }
+
+ virtual void remove(CharSourceRange range) {
+ assert(Ctx);
+ OS << "Remove: ";
+ printSourceRange(range, *Ctx, OS);
+ OS << '\n';
+ }
+};
+
+} // anonymous namespace
+
+static bool checkForMigration(llvm::StringRef resourcesPath,
+ llvm::ArrayRef<const char *> Args) {
+ DiagnosticClient *DiagClient =
+ new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions());
+ llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ llvm::IntrusiveRefCntPtr<Diagnostic> Diags(new Diagnostic(DiagID, DiagClient));
+ // Chain in -verify checker, if requested.
+ VerifyDiagnosticsClient *verifyDiag = 0;
+ if (VerifyDiags) {
+ verifyDiag = new VerifyDiagnosticsClient(*Diags, Diags->takeClient());
+ Diags->setClient(verifyDiag);
+ }
+
+ CompilerInvocation CI;
+ CompilerInvocation::CreateFromArgs(CI, Args.begin(), Args.end(), *Diags);
+
+ if (CI.getFrontendOpts().Inputs.empty()) {
+ llvm::errs() << "error: no input files\n";
+ return true;
+ }
+
+ if (!CI.getLangOpts().ObjC1)
+ return false;
+
+ arcmt::checkForManualIssues(CI,
+ CI.getFrontendOpts().Inputs[0].second,
+ CI.getFrontendOpts().Inputs[0].first,
+ Diags->getClient());
+ return Diags->getClient()->getNumErrors() > 0;
+}
+
+static void printResult(FileRemapper &remapper, llvm::raw_ostream &OS) {
+ CompilerInvocation CI;
+ remapper.applyMappings(CI);
+ PreprocessorOptions &PPOpts = CI.getPreprocessorOpts();
+ // The changed files will be in memory buffers, print them.
+ for (unsigned i = 0, e = PPOpts.RemappedFileBuffers.size(); i != e; ++i) {
+ const llvm::MemoryBuffer *mem = PPOpts.RemappedFileBuffers[i].second;
+ OS << mem->getBuffer();
+ }
+}
+
+static bool performTransformations(llvm::StringRef resourcesPath,
+ llvm::ArrayRef<const char *> Args) {
+ // Check first.
+ if (checkForMigration(resourcesPath, Args))
+ return true;
+
+ DiagnosticClient *DiagClient =
+ new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions());
+ llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ llvm::IntrusiveRefCntPtr<Diagnostic> TopDiags(new Diagnostic(DiagID, DiagClient));
+
+ CompilerInvocation origCI;
+ CompilerInvocation::CreateFromArgs(origCI, Args.begin(), Args.end(),
+ *TopDiags);
+
+ if (origCI.getFrontendOpts().Inputs.empty()) {
+ llvm::errs() << "error: no input files\n";
+ return true;
+ }
+
+ if (!origCI.getLangOpts().ObjC1)
+ return false;
+
+ MigrationProcess migration(origCI, DiagClient);
+
+ std::vector<TransformFn> transforms = arcmt::getAllTransformations();
+ assert(!transforms.empty());
+
+ llvm::OwningPtr<PrintTransforms> transformPrinter;
+ if (OutputTransformations)
+ transformPrinter.reset(new PrintTransforms(llvm::outs()));
+
+ for (unsigned i=0, e = transforms.size(); i != e; ++i) {
+ bool err = migration.applyTransform(transforms[i], transformPrinter.get());
+ if (err) return true;
+
+ if (VerboseOpt) {
+ if (i == e-1)
+ llvm::errs() << "\n##### FINAL RESULT #####\n";
+ else
+ llvm::errs() << "\n##### OUTPUT AFTER "<< i+1 <<". TRANSFORMATION #####\n";
+ printResult(migration.getRemapper(), llvm::errs());
+ llvm::errs() << "\n##########################\n\n";
+ }
+ }
+
+ if (!OutputTransformations)
+ printResult(migration.getRemapper(), llvm::outs());
+
+ // FIXME: TestResultForARC
+
+ return false;
+}
+
+static bool filesCompareEqual(llvm::StringRef fname1, llvm::StringRef fname2) {
+ using namespace llvm;
+
+ OwningPtr<MemoryBuffer> file1;
+ MemoryBuffer::getFile(fname1, file1);
+ if (!file1)
+ return false;
+
+ OwningPtr<MemoryBuffer> file2;
+ MemoryBuffer::getFile(fname2, file2);
+ if (!file2)
+ return false;
+
+ return file1->getBuffer() == file2->getBuffer();
+}
+
+static bool verifyTransformedFiles(llvm::ArrayRef<std::string> resultFiles) {
+ using namespace llvm;
+
+ assert(!resultFiles.empty());
+
+ std::map<StringRef, StringRef> resultMap;
+
+ for (ArrayRef<std::string>::iterator
+ I = resultFiles.begin(), E = resultFiles.end(); I != E; ++I) {
+ StringRef fname(*I);
+ if (!fname.endswith(".result")) {
+ errs() << "error: filename '" << fname
+ << "' does not have '.result' extension\n";
+ return true;
+ }
+ resultMap[sys::path::stem(fname)] = fname;
+ }
+
+ OwningPtr<MemoryBuffer> inputBuf;
+ if (RemappingsFile.empty())
+ MemoryBuffer::getSTDIN(inputBuf);
+ else
+ MemoryBuffer::getFile(RemappingsFile, inputBuf);
+ if (!inputBuf) {
+ errs() << "error: could not read remappings input\n";
+ return true;
+ }
+
+ SmallVector<StringRef, 8> strs;
+ inputBuf->getBuffer().split(strs, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
+
+ if (strs.empty()) {
+ errs() << "error: no files to verify from stdin\n";
+ return true;
+ }
+ if (strs.size() % 2 != 0) {
+ errs() << "error: files to verify are not original/result pairs\n";
+ return true;
+ }
+
+ for (unsigned i = 0, e = strs.size(); i != e; i += 2) {
+ StringRef inputOrigFname = strs[i];
+ StringRef inputResultFname = strs[i+1];
+
+ std::map<StringRef, StringRef>::iterator It;
+ It = resultMap.find(sys::path::filename(inputOrigFname));
+ if (It == resultMap.end()) {
+ errs() << "error: '" << inputOrigFname << "' is not in the list of "
+ << "transformed files to verify\n";
+ return true;
+ }
+
+ bool exists = false;
+ sys::fs::exists(It->second, exists);
+ if (!exists) {
+ errs() << "error: '" << It->second << "' does not exist\n";
+ return true;
+ }
+ sys::fs::exists(inputResultFname, exists);
+ if (!exists) {
+ errs() << "error: '" << inputResultFname << "' does not exist\n";
+ return true;
+ }
+
+ if (!filesCompareEqual(It->second, inputResultFname)) {
+ errs() << "error: '" << It->second << "' is different than "
+ << "'" << inputResultFname << "'\n";
+ return true;
+ }
+
+ resultMap.erase(It);
+ }
+
+ if (!resultMap.empty()) {
+ for (std::map<StringRef, StringRef>::iterator
+ I = resultMap.begin(), E = resultMap.end(); I != E; ++I)
+ errs() << "error: '" << I->second << "' was not verified!\n";
+ return true;
+ }
+
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
+// Misc. functions.
+//===----------------------------------------------------------------------===//
+
+static void printSourceLocation(SourceLocation loc, ASTContext &Ctx,
+ llvm::raw_ostream &OS) {
+ SourceManager &SM = Ctx.getSourceManager();
+ PresumedLoc PL = SM.getPresumedLoc(loc);
+
+ OS << llvm::sys::path::filename(PL.getFilename());
+ OS << ":" << PL.getLine() << ":"
+ << PL.getColumn();
+}
+
+static void printSourceRange(CharSourceRange range, ASTContext &Ctx,
+ llvm::raw_ostream &OS) {
+ SourceManager &SM = Ctx.getSourceManager();
+ const LangOptions &langOpts = Ctx.getLangOptions();
+
+ PresumedLoc PL = SM.getPresumedLoc(range.getBegin());
+
+ OS << llvm::sys::path::filename(PL.getFilename());
+ OS << " [" << PL.getLine() << ":"
+ << PL.getColumn();
+ OS << " - ";
+
+ SourceLocation end = range.getEnd();
+ PL = SM.getPresumedLoc(end);
+
+ unsigned endCol = PL.getColumn() - 1;
+ if (!range.isTokenRange())
+ endCol += Lexer::MeasureTokenLength(end, SM, langOpts);
+ OS << PL.getLine() << ":" << endCol << "]";
+}
+
+//===----------------------------------------------------------------------===//
+// Command line processing.
+//===----------------------------------------------------------------------===//
+
+int main(int argc, const char **argv) {
+ using llvm::StringRef;
+ void *MainAddr = (void*) (intptr_t) GetExecutablePath;
+ llvm::sys::PrintStackTraceOnErrorSignal();
+
+ std::string
+ resourcesPath = CompilerInvocation::GetResourcesPath(argv[0], MainAddr);
+
+ int optargc = 0;
+ for (; optargc != argc; ++optargc) {
+ if (StringRef(argv[optargc]) == "--args")
+ break;
+ }
+ llvm::cl::ParseCommandLineOptions(optargc, const_cast<char **>(argv), "arcmt-test");
+
+ if (VerifyTransformedFiles) {
+ if (ResultFiles.empty()) {
+ llvm::cl::PrintHelpMessage();
+ return 1;
+ }
+ return verifyTransformedFiles(ResultFiles);
+ }
+
+ if (optargc == argc) {
+ llvm::cl::PrintHelpMessage();
+ return 1;
+ }
+
+ llvm::ArrayRef<const char*> Args(argv+optargc+1, argc-optargc-1);
+
+ if (CheckOnly)
+ return checkForMigration(resourcesPath, Args);
+
+ return performTransformations(resourcesPath, Args);
+}
diff --git a/tools/c-arcmt-test/CMakeLists.txt b/tools/c-arcmt-test/CMakeLists.txt
new file mode 100644
index 000000000000..351f4adca10f
--- /dev/null
+++ b/tools/c-arcmt-test/CMakeLists.txt
@@ -0,0 +1,14 @@
+set(LLVM_USED_LIBS libclang)
+
+set( LLVM_LINK_COMPONENTS
+ support
+ mc
+ )
+
+add_clang_executable(c-arcmt-test
+ c-arcmt-test.c
+ )
+
+set_target_properties(c-arcmt-test
+ PROPERTIES
+ LINKER_LANGUAGE CXX)
diff --git a/tools/c-arcmt-test/Makefile b/tools/c-arcmt-test/Makefile
new file mode 100644
index 000000000000..b72a08ab53bb
--- /dev/null
+++ b/tools/c-arcmt-test/Makefile
@@ -0,0 +1,25 @@
+##===- tools/c-arcmt-test/Makefile -------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+CLANG_LEVEL := ../..
+
+TOOLNAME = c-arcmt-test
+
+# No plugins, optimize startup time.
+TOOL_NO_EXPORTS = 1
+
+# Don't install this. It is used for tests.
+NO_INSTALL = 1
+
+LINK_COMPONENTS := support mc
+USEDLIBS = clang.a clangIndex.a clangARCMigrate.a clangRewrite.a \
+ clangFrontend.a clangDriver.a \
+ clangSerialization.a clangParse.a clangSema.a \
+ clangAnalysis.a clangAST.a clangLex.a clangBasic.a
+
+include $(CLANG_LEVEL)/Makefile
diff --git a/tools/c-arcmt-test/c-arcmt-test.c b/tools/c-arcmt-test/c-arcmt-test.c
new file mode 100644
index 000000000000..5522b33e23a5
--- /dev/null
+++ b/tools/c-arcmt-test/c-arcmt-test.c
@@ -0,0 +1,91 @@
+/* c-arcmt-test.c */
+
+#include "clang-c/Index.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#if defined(_WIN32)
+#include <io.h>
+#include <fcntl.h>
+#endif
+
+static int print_remappings(const char *path) {
+ CXRemapping remap;
+ unsigned i, N;
+ CXString origFname;
+ CXString transFname;
+
+ remap = clang_getRemappings(path);
+ if (!remap)
+ return 1;
+
+ N = clang_remap_getNumFiles(remap);
+ for (i = 0; i != N; ++i) {
+ clang_remap_getFilenames(remap, i, &origFname, &transFname);
+
+ fprintf(stdout, "%s\n", clang_getCString(origFname));
+ fprintf(stdout, "%s\n", clang_getCString(transFname));
+
+ clang_disposeString(origFname);
+ clang_disposeString(transFname);
+ }
+
+ clang_remap_dispose(remap);
+ return 0;
+}
+
+/******************************************************************************/
+/* Command line processing. */
+/******************************************************************************/
+
+static void print_usage(void) {
+ fprintf(stderr,
+ "usage: c-arcmt-test -arcmt-migrate-directory <path>\n\n\n");
+}
+
+/***/
+
+int carcmttest_main(int argc, const char **argv) {
+ clang_enableStackTraces();
+ if (argc == 3 && strncmp(argv[1], "-arcmt-migrate-directory", 24) == 0)
+ return print_remappings(argv[2]);
+
+ print_usage();
+ return 1;
+}
+
+/***/
+
+/* We intentionally run in a separate thread to ensure we at least minimal
+ * testing of a multithreaded environment (for example, having a reduced stack
+ * size). */
+
+typedef struct thread_info {
+ int argc;
+ const char **argv;
+ int result;
+} thread_info;
+void thread_runner(void *client_data_v) {
+ thread_info *client_data = client_data_v;
+ client_data->result = carcmttest_main(client_data->argc, client_data->argv);
+}
+
+int main(int argc, const char **argv) {
+ thread_info client_data;
+
+#if defined(_WIN32)
+ if (getenv("LIBCLANG_LOGGING") == NULL)
+ putenv("LIBCLANG_LOGGING=1");
+ _setmode( _fileno(stdout), _O_BINARY );
+#else
+ setenv("LIBCLANG_LOGGING", "1", /*overwrite=*/0);
+#endif
+
+ if (getenv("CINDEXTEST_NOTHREADS"))
+ return carcmttest_main(argc, argv);
+
+ client_data.argc = argc;
+ client_data.argv = argv;
+ clang_executeOnThread(thread_runner, &client_data, 0);
+ return client_data.result;
+}
diff --git a/tools/c-index-test/Makefile b/tools/c-index-test/Makefile
index 68064041f435..5e5b8570c812 100644
--- a/tools/c-index-test/Makefile
+++ b/tools/c-index-test/Makefile
@@ -18,7 +18,7 @@ NO_INSTALL = 1
LINK_COMPONENTS := support mc
USEDLIBS = clang.a clangIndex.a clangFrontend.a clangDriver.a \
- clangSerialization.a clangParse.a clangSema.a clangAnalysis.a \
- clangAST.a clangLex.a clangBasic.a
+ clangSerialization.a clangParse.a clangSema.a \
+ clangAnalysis.a clangAST.a clangLex.a clangBasic.a
include $(CLANG_LEVEL)/Makefile
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c
index 837fc8929e52..6e0aaac73cc3 100644
--- a/tools/c-index-test/c-index-test.c
+++ b/tools/c-index-test/c-index-test.c
@@ -38,7 +38,7 @@ static unsigned getDefaultParsingOptions() {
if (getenv("CINDEXTEST_COMPLETION_CACHING"))
options |= CXTranslationUnit_CacheCompletionResults;
if (getenv("CINDEXTEST_NESTED_MACROS"))
- options |= CXTranslationUnit_NestedMacroInstantiations;
+ options |= CXTranslationUnit_NestedMacroExpansions;
return options;
}
@@ -1018,6 +1018,79 @@ void print_completion_result(CXCompletionResult *completion_result,
fprintf(file, "\n");
}
+void print_completion_contexts(unsigned long long contexts, FILE *file) {
+ fprintf(file, "Completion contexts:\n");
+ if (contexts == CXCompletionContext_Unknown) {
+ fprintf(file, "Unknown\n");
+ }
+ if (contexts & CXCompletionContext_AnyType) {
+ fprintf(file, "Any type\n");
+ }
+ if (contexts & CXCompletionContext_AnyValue) {
+ fprintf(file, "Any value\n");
+ }
+ if (contexts & CXCompletionContext_ObjCObjectValue) {
+ fprintf(file, "Objective-C object value\n");
+ }
+ if (contexts & CXCompletionContext_ObjCSelectorValue) {
+ fprintf(file, "Objective-C selector value\n");
+ }
+ if (contexts & CXCompletionContext_CXXClassTypeValue) {
+ fprintf(file, "C++ class type value\n");
+ }
+ if (contexts & CXCompletionContext_DotMemberAccess) {
+ fprintf(file, "Dot member access\n");
+ }
+ if (contexts & CXCompletionContext_ArrowMemberAccess) {
+ fprintf(file, "Arrow member access\n");
+ }
+ if (contexts & CXCompletionContext_ObjCPropertyAccess) {
+ fprintf(file, "Objective-C property access\n");
+ }
+ if (contexts & CXCompletionContext_EnumTag) {
+ fprintf(file, "Enum tag\n");
+ }
+ if (contexts & CXCompletionContext_UnionTag) {
+ fprintf(file, "Union tag\n");
+ }
+ if (contexts & CXCompletionContext_StructTag) {
+ fprintf(file, "Struct tag\n");
+ }
+ if (contexts & CXCompletionContext_ClassTag) {
+ fprintf(file, "Class name\n");
+ }
+ if (contexts & CXCompletionContext_Namespace) {
+ fprintf(file, "Namespace or namespace alias\n");
+ }
+ if (contexts & CXCompletionContext_NestedNameSpecifier) {
+ fprintf(file, "Nested name specifier\n");
+ }
+ if (contexts & CXCompletionContext_ObjCInterface) {
+ fprintf(file, "Objective-C interface\n");
+ }
+ if (contexts & CXCompletionContext_ObjCProtocol) {
+ fprintf(file, "Objective-C protocol\n");
+ }
+ if (contexts & CXCompletionContext_ObjCCategory) {
+ fprintf(file, "Objective-C category\n");
+ }
+ if (contexts & CXCompletionContext_ObjCInstanceMessage) {
+ fprintf(file, "Objective-C instance method\n");
+ }
+ if (contexts & CXCompletionContext_ObjCClassMessage) {
+ fprintf(file, "Objective-C class method\n");
+ }
+ if (contexts & CXCompletionContext_ObjCSelectorName) {
+ fprintf(file, "Objective-C selector name\n");
+ }
+ if (contexts & CXCompletionContext_MacroName) {
+ fprintf(file, "Macro name\n");
+ }
+ if (contexts & CXCompletionContext_NaturalLanguage) {
+ fprintf(file, "Natural language\n");
+ }
+}
+
int my_stricmp(const char *s1, const char *s2) {
while (*s1 && *s2) {
int c1 = tolower((unsigned char)*s1), c2 = tolower((unsigned char)*s2);
@@ -1099,6 +1172,7 @@ int perform_code_completion(int argc, const char **argv, int timing_only) {
if (results) {
unsigned i, n = results->NumResults;
+ unsigned long long contexts;
if (!timing_only) {
/* Sort the code-completion results based on the typed text. */
clang_sortCodeCompletionResults(results->Results, results->NumResults);
@@ -1112,6 +1186,10 @@ int perform_code_completion(int argc, const char **argv, int timing_only) {
PrintDiagnostic(diag);
clang_disposeDiagnostic(diag);
}
+
+ contexts = clang_codeCompleteGetContexts(results);
+ print_completion_contexts(contexts, stdout);
+
clang_disposeCodeCompleteResults(results);
}
clang_disposeTranslationUnit(TU);
@@ -1496,6 +1574,7 @@ int write_pch_file(const char *filename, int argc, const char *argv[]) {
CXTranslationUnit TU;
struct CXUnsavedFile *unsaved_files = 0;
int num_unsaved_files = 0;
+ int result = 0;
Idx = clang_createIndex(/* excludeDeclsFromPCH */1, /* displayDiagnosics=*/1);
@@ -1517,12 +1596,34 @@ int write_pch_file(const char *filename, int argc, const char *argv[]) {
return 1;
}
- if (clang_saveTranslationUnit(TU, filename, clang_defaultSaveOptions(TU)))
- fprintf(stderr, "Unable to write PCH file %s\n", filename);
+ switch (clang_saveTranslationUnit(TU, filename,
+ clang_defaultSaveOptions(TU))) {
+ case CXSaveError_None:
+ break;
+
+ case CXSaveError_TranslationErrors:
+ fprintf(stderr, "Unable to write PCH file %s: translation errors\n",
+ filename);
+ result = 2;
+ break;
+
+ case CXSaveError_InvalidTU:
+ fprintf(stderr, "Unable to write PCH file %s: invalid translation unit\n",
+ filename);
+ result = 3;
+ break;
+
+ case CXSaveError_Unknown:
+ default:
+ fprintf(stderr, "Unable to write PCH file %s: unknown error \n", filename);
+ result = 1;
+ break;
+ }
+
clang_disposeTranslationUnit(TU);
free_remapped_files(unsaved_files, num_unsaved_files);
clang_disposeIndex(Idx);
- return 0;
+ return result;
}
/******************************************************************************/
diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt
index 0c41490175e9..e6d0f1ac3763 100644
--- a/tools/driver/CMakeLists.txt
+++ b/tools/driver/CMakeLists.txt
@@ -9,6 +9,7 @@ set( LLVM_USED_LIBS
clangIndex
clangLex
clangParse
+ clangARCMigrate
clangRewrite
clangSema
clangSerialization
diff --git a/tools/driver/Makefile b/tools/driver/Makefile
index abe70983df42..1ba8bc24d1fb 100644
--- a/tools/driver/Makefile
+++ b/tools/driver/Makefile
@@ -41,7 +41,7 @@ USEDLIBS = clangFrontendTool.a clangFrontend.a clangDriver.a \
clangSerialization.a clangCodeGen.a clangParse.a clangSema.a \
clangStaticAnalyzerFrontend.a clangStaticAnalyzerCheckers.a \
clangStaticAnalyzerCore.a \
- clangAnalysis.a clangIndex.a clangRewrite.a \
+ clangAnalysis.a clangIndex.a clangARCMigrate.a clangRewrite.a \
clangAST.a clangLex.a clangBasic.a
include $(CLANG_LEVEL)/Makefile
diff --git a/tools/driver/cc1_main.cpp b/tools/driver/cc1_main.cpp
index 535eaa9c96f8..9ad4af1436ca 100644
--- a/tools/driver/cc1_main.cpp
+++ b/tools/driver/cc1_main.cpp
@@ -126,6 +126,8 @@ int cc1_main(const char **ArgBegin, const char **ArgEnd,
// Initialize targets first, so that --version shows registered targets.
llvm::InitializeAllTargets();
+ llvm::InitializeAllMCAsmInfos();
+ llvm::InitializeAllMCSubtargetInfos();
llvm::InitializeAllAsmPrinters();
llvm::InitializeAllAsmParsers();
diff --git a/tools/driver/cc1as_main.cpp b/tools/driver/cc1as_main.cpp
index f449235db4c4..358d746986c8 100644
--- a/tools/driver/cc1as_main.cpp
+++ b/tools/driver/cc1as_main.cpp
@@ -29,7 +29,9 @@
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/ErrorHandling.h"
@@ -47,11 +49,13 @@
#include "llvm/Target/TargetAsmInfo.h"
#include "llvm/Target/TargetAsmParser.h"
#include "llvm/Target/TargetData.h"
+#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetLowering.h"
#include "llvm/Target/TargetLoweringObjectFile.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetRegistry.h"
#include "llvm/Target/TargetSelect.h"
+#include "llvm/Target/TargetSubtargetInfo.h"
using namespace clang;
using namespace clang::driver;
using namespace llvm;
@@ -252,7 +256,7 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts, Diagnostic &Diags) {
// it later.
SrcMgr.setIncludeDirs(Opts.IncludePaths);
- OwningPtr<MCAsmInfo> MAI(TheTarget->createAsmInfo(Opts.Triple));
+ OwningPtr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(Opts.Triple));
assert(MAI && "Unable to create target asm info!");
bool IsBinary = Opts.OutputType == AssemblerInvocation::FT_Obj;
@@ -261,7 +265,8 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts, Diagnostic &Diags) {
return false;
// FIXME: We shouldn't need to do this (and link in codegen).
- OwningPtr<TargetMachine> TM(TheTarget->createTargetMachine(Opts.Triple, ""));
+ OwningPtr<TargetMachine> TM(TheTarget->createTargetMachine(Opts.Triple,
+ "", ""));
if (!TM) {
Diags.Report(diag::err_target_unknown_triple) << Opts.Triple;
return false;
@@ -278,14 +283,16 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts, Diagnostic &Diags) {
TM->getTargetLowering()->getObjFileLowering();
const_cast<TargetLoweringObjectFile&>(TLOF).Initialize(Ctx, *TM);
+ const MCSubtargetInfo &STI = TM->getSubtarget<MCSubtargetInfo>();
+
// FIXME: There is a bit of code duplication with addPassesToEmitFile.
if (Opts.OutputType == AssemblerInvocation::FT_Asm) {
MCInstPrinter *IP =
- TheTarget->createMCInstPrinter(*TM, Opts.OutputAsmVariant, *MAI);
+ TheTarget->createMCInstPrinter(Opts.OutputAsmVariant, *MAI);
MCCodeEmitter *CE = 0;
TargetAsmBackend *TAB = 0;
if (Opts.ShowEncoding) {
- CE = TheTarget->createCodeEmitter(*TM, Ctx);
+ CE = TheTarget->createCodeEmitter(*TM->getInstrInfo(), STI, Ctx);
TAB = TheTarget->createAsmBackend(Opts.Triple);
}
Str.reset(TheTarget->createAsmStreamer(Ctx, *Out, /*asmverbose*/true,
@@ -297,7 +304,8 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts, Diagnostic &Diags) {
} else {
assert(Opts.OutputType == AssemblerInvocation::FT_Obj &&
"Invalid file type!");
- MCCodeEmitter *CE = TheTarget->createCodeEmitter(*TM, Ctx);
+ MCCodeEmitter *CE = TheTarget->createCodeEmitter(*TM->getInstrInfo(),
+ STI, Ctx);
TargetAsmBackend *TAB = TheTarget->createAsmBackend(Opts.Triple);
Str.reset(TheTarget->createObjectStreamer(Opts.Triple, Ctx, *TAB, *Out,
CE, Opts.RelaxAll,
@@ -307,7 +315,8 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts, Diagnostic &Diags) {
OwningPtr<MCAsmParser> Parser(createMCAsmParser(*TheTarget, SrcMgr, Ctx,
*Str.get(), *MAI));
- OwningPtr<TargetAsmParser> TAP(TheTarget->createAsmParser(*Parser, *TM));
+ OwningPtr<TargetAsmParser>
+ TAP(TheTarget->createAsmParser(const_cast<MCSubtargetInfo&>(STI), *Parser));
if (!TAP) {
Diags.Report(diag::err_target_unknown_triple) << Opts.Triple;
return false;
@@ -347,6 +356,9 @@ int cc1as_main(const char **ArgBegin, const char **ArgEnd,
InitializeAllTargetInfos();
// FIXME: We shouldn't need to initialize the Target(Machine)s.
InitializeAllTargets();
+ InitializeAllMCAsmInfos();
+ InitializeAllMCInstrInfos();
+ InitializeAllMCSubtargetInfos();
InitializeAllAsmPrinters();
InitializeAllAsmParsers();
diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp
index db72da42ea34..ca8982619e94 100644
--- a/tools/driver/driver.cpp
+++ b/tools/driver/driver.cpp
@@ -327,9 +327,11 @@ static void ParseProgName(llvm::SmallVectorImpl<const char *> &ArgVector,
std::string IgnoredError;
if (llvm::TargetRegistry::lookupTarget(Prefix, IgnoredError)) {
- ArgVector.insert(&ArgVector[1],
- SaveStringInSet(SavedStrings, Prefix));
- ArgVector.insert(&ArgVector[1],
+ llvm::SmallVectorImpl<const char *>::iterator it = ArgVector.begin();
+ if (it != ArgVector.end())
+ ++it;
+ ArgVector.insert(it, SaveStringInSet(SavedStrings, Prefix));
+ ArgVector.insert(it,
SaveStringInSet(SavedStrings, std::string("-ccc-host-triple")));
}
}
diff --git a/tools/libclang/ARCMigrate.cpp b/tools/libclang/ARCMigrate.cpp
new file mode 100644
index 000000000000..39c7d84d5190
--- /dev/null
+++ b/tools/libclang/ARCMigrate.cpp
@@ -0,0 +1,98 @@
+//===- ARCMigrate.cpp - Clang-C ARC Migration Library ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the main API hooks in the Clang-C ARC Migration library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang-c/Index.h"
+
+#include "CXString.h"
+#include "clang/ARCMigrate/ARCMT.h"
+#include "clang/Frontend/TextDiagnosticBuffer.h"
+#include "llvm/Support/FileSystem.h"
+
+using namespace clang;
+using namespace arcmt;
+
+namespace {
+
+struct Remap {
+ std::vector<std::pair<std::string, std::string> > Vec;
+};
+
+} // anonymous namespace.
+
+//===----------------------------------------------------------------------===//
+// libClang public APIs.
+//===----------------------------------------------------------------------===//
+
+extern "C" {
+
+CXRemapping clang_getRemappings(const char *migrate_dir_path) {
+ bool Logging = ::getenv("LIBCLANG_LOGGING");
+
+ if (!migrate_dir_path) {
+ if (Logging)
+ llvm::errs() << "clang_getRemappings was called with NULL parameter\n";
+ return 0;
+ }
+
+ bool exists = false;
+ llvm::sys::fs::exists(migrate_dir_path, exists);
+ if (!exists) {
+ if (Logging) {
+ llvm::errs() << "Error by clang_getRemappings(\"" << migrate_dir_path
+ << "\")\n";
+ llvm::errs() << "\"" << migrate_dir_path << "\" does not exist\n";
+ }
+ return 0;
+ }
+
+ TextDiagnosticBuffer diagBuffer;
+ llvm::OwningPtr<Remap> remap(new Remap());
+
+ bool err = arcmt::getFileRemappings(remap->Vec, migrate_dir_path,&diagBuffer);
+
+ if (err) {
+ if (Logging) {
+ llvm::errs() << "Error by clang_getRemappings(\"" << migrate_dir_path
+ << "\")\n";
+ for (TextDiagnosticBuffer::const_iterator
+ I = diagBuffer.err_begin(), E = diagBuffer.err_end(); I != E; ++I)
+ llvm::errs() << I->second << '\n';
+ }
+ return 0;
+ }
+
+ return remap.take();
+}
+
+unsigned clang_remap_getNumFiles(CXRemapping map) {
+ return static_cast<Remap *>(map)->Vec.size();
+
+}
+
+void clang_remap_getFilenames(CXRemapping map, unsigned index,
+ CXString *original, CXString *transformed) {
+ if (original)
+ *original = cxstring::createCXString(
+ static_cast<Remap *>(map)->Vec[index].first,
+ /*DupString =*/ true);
+ if (transformed)
+ *transformed = cxstring::createCXString(
+ static_cast<Remap *>(map)->Vec[index].second,
+ /*DupString =*/ true);
+}
+
+void clang_remap_dispose(CXRemapping map) {
+ delete static_cast<Remap *>(map);
+}
+
+} // end: extern "C"
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index 2a9d96db4c35..50d56fccb9c5 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -544,8 +544,8 @@ bool CursorVisitor::VisitChildren(CXCursor Cursor) {
// do so.
PreprocessingRecord::iterator E, EEnd;
for (llvm::tie(E, EEnd) = getPreprocessedEntities(); E != EEnd; ++E) {
- if (MacroInstantiation *MI = dyn_cast<MacroInstantiation>(*E)) {
- if (Visit(MakeMacroInstantiationCursor(MI, tu)))
+ if (MacroExpansion *ME = dyn_cast<MacroExpansion>(*E)) {
+ if (Visit(MakeMacroExpansionCursor(ME, tu)))
return true;
continue;
@@ -1330,6 +1330,11 @@ bool CursorVisitor::VisitTemplateName(TemplateName Name, SourceLocation Loc) {
return Visit(MakeCursorTemplateRef(
Name.getAsQualifiedTemplateName()->getDecl(),
Loc, TU));
+
+ case TemplateName::SubstTemplateTemplateParm:
+ return Visit(MakeCursorTemplateRef(
+ Name.getAsSubstTemplateTemplateParm()->getParameter(),
+ Loc, TU));
case TemplateName::SubstTemplateTemplateParmPack:
return Visit(MakeCursorTemplateRef(
@@ -2374,7 +2379,8 @@ CXTranslationUnit clang_createTranslationUnit(CXIndex CIdx,
unsigned clang_defaultEditingTranslationUnitOptions() {
return CXTranslationUnit_PrecompiledPreamble |
CXTranslationUnit_CacheCompletionResults |
- CXTranslationUnit_CXXPrecompiledPreamble;
+ CXTranslationUnit_CXXPrecompiledPreamble |
+ CXTranslationUnit_CXXChainedPCH;
}
CXTranslationUnit
@@ -2385,7 +2391,7 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx,
unsigned num_unsaved_files,
struct CXUnsavedFile *unsaved_files) {
unsigned Options = CXTranslationUnit_DetailedPreprocessingRecord |
- CXTranslationUnit_NestedMacroInstantiations;
+ CXTranslationUnit_NestedMacroExpansions;
return clang_parseTranslationUnit(CIdx, source_filename,
command_line_args, num_command_line_args,
unsaved_files, num_unsaved_files,
@@ -2490,12 +2496,12 @@ static void clang_parseTranslationUnit_Impl(void *UserData) {
Args->push_back(source_filename);
// Do we need the detailed preprocessing record?
- bool NestedMacroInstantiations = false;
+ bool NestedMacroExpansions = false;
if (options & CXTranslationUnit_DetailedPreprocessingRecord) {
Args->push_back("-Xclang");
Args->push_back("-detailed-preprocessing-record");
- NestedMacroInstantiations
- = (options & CXTranslationUnit_NestedMacroInstantiations);
+ NestedMacroExpansions
+ = (options & CXTranslationUnit_NestedMacroExpansions);
}
unsigned NumErrors = Diags->getClient()->getNumErrors();
@@ -2515,7 +2521,7 @@ static void clang_parseTranslationUnit_Impl(void *UserData) {
CacheCodeCompetionResults,
CXXPrecompilePreamble,
CXXChainedPCH,
- NestedMacroInstantiations));
+ NestedMacroExpansions));
if (NumErrors != Diags->getClient()->getNumErrors()) {
// Make sure to check that 'Unit' is non-NULL.
@@ -2588,9 +2594,9 @@ unsigned clang_defaultSaveOptions(CXTranslationUnit TU) {
int clang_saveTranslationUnit(CXTranslationUnit TU, const char *FileName,
unsigned options) {
if (!TU)
- return 1;
+ return CXSaveError_InvalidTU;
- int result = static_cast<ASTUnit *>(TU->TUData)->Save(FileName);
+ CXSaveError result = static_cast<ASTUnit *>(TU->TUData)->Save(FileName);
if (getenv("LIBCLANG_RESOURCE_USAGE"))
PrintLibclangResourceUsage(TU);
return result;
@@ -2800,7 +2806,7 @@ void clang_getInstantiationLocation(CXSourceLocation location,
*static_cast<const SourceManager*>(location.ptr_data[0]);
SourceLocation InstLoc = SM.getInstantiationLoc(Loc);
- // Check that the FileID is invalid on the instantiation location.
+ // Check that the FileID is invalid on the expansion location.
// This can manifest in invalid code.
FileID fileID = SM.getFileID(InstLoc);
bool Invalid = false;
@@ -3145,8 +3151,8 @@ CXString clang_getCursorSpelling(CXCursor C) {
return createCXString("");
}
- if (C.kind == CXCursor_MacroInstantiation)
- return createCXString(getCursorMacroInstantiation(C)->getName()
+ if (C.kind == CXCursor_MacroExpansion)
+ return createCXString(getCursorMacroExpansion(C)->getName()
->getNameStart());
if (C.kind == CXCursor_MacroDefinition)
@@ -3346,8 +3352,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return createCXString("preprocessing directive");
case CXCursor_MacroDefinition:
return createCXString("macro definition");
- case CXCursor_MacroInstantiation:
- return createCXString("macro instantiation");
+ case CXCursor_MacroExpansion:
+ return createCXString("macro expansion");
case CXCursor_InclusionDirective:
return createCXString("inclusion directive");
case CXCursor_Namespace:
@@ -3392,11 +3398,34 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return createCXString((const char*) 0);
}
+struct GetCursorData {
+ SourceLocation TokenBeginLoc;
+ CXCursor &BestCursor;
+
+ GetCursorData(SourceLocation tokenBegin, CXCursor &outputCursor)
+ : TokenBeginLoc(tokenBegin), BestCursor(outputCursor) { }
+};
+
enum CXChildVisitResult GetCursorVisitor(CXCursor cursor,
CXCursor parent,
CXClientData client_data) {
- CXCursor *BestCursor = static_cast<CXCursor *>(client_data);
-
+ GetCursorData *Data = static_cast<GetCursorData *>(client_data);
+ CXCursor *BestCursor = &Data->BestCursor;
+
+ if (clang_isExpression(cursor.kind) &&
+ clang_isDeclaration(BestCursor->kind)) {
+ Decl *D = getCursorDecl(*BestCursor);
+
+ // Avoid having the cursor of an expression replace the declaration cursor
+ // when the expression source range overlaps the declaration range.
+ // This can happen for C++ constructor expressions whose range generally
+ // include the variable declaration, e.g.:
+ // MyCXXClass foo; // Make sure pointing at 'foo' returns a VarDecl cursor.
+ if (D->getLocation().isValid() && Data->TokenBeginLoc.isValid() &&
+ D->getLocation() == Data->TokenBeginLoc)
+ return CXChildVisit_Break;
+ }
+
// If our current best cursor is the construction of a temporary object,
// don't replace that cursor with a type reference, because we want
// clang_getCursor() to point at the constructor.
@@ -3440,8 +3469,9 @@ CXCursor clang_getCursor(CXTranslationUnit TU, CXSourceLocation Loc) {
// FIXME: Would be great to have a "hint" cursor, then walk from that
// hint cursor upward until we find a cursor whose source range encloses
// the region of interest, rather than starting from the translation unit.
+ GetCursorData ResultData(SLoc, Result);
CXCursor Parent = clang_getTranslationUnitCursor(TU);
- CursorVisitor CursorVis(TU, GetCursorVisitor, &Result,
+ CursorVisitor CursorVis(TU, GetCursorVisitor, &ResultData,
Decl::MaxPCHLevel, true, SourceLocation(SLoc));
CursorVis.VisitChildren(Parent);
}
@@ -3532,6 +3562,10 @@ unsigned clang_isStatement(enum CXCursorKind K) {
return K >= CXCursor_FirstStmt && K <= CXCursor_LastStmt;
}
+unsigned clang_isAttribute(enum CXCursorKind K) {
+ return K >= CXCursor_FirstAttr && K <= CXCursor_LastAttr;
+}
+
unsigned clang_isTranslationUnit(enum CXCursorKind K) {
return K == CXCursor_TranslationUnit;
}
@@ -3638,9 +3672,9 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) {
return cxloc::translateSourceLocation(getCursorContext(C), L);
}
- if (C.kind == CXCursor_MacroInstantiation) {
+ if (C.kind == CXCursor_MacroExpansion) {
SourceLocation L
- = cxcursor::getCursorMacroInstantiation(C)->getSourceRange().getBegin();
+ = cxcursor::getCursorMacroExpansion(C)->getSourceRange().getBegin();
return cxloc::translateSourceLocation(getCursorContext(C), L);
}
@@ -3725,8 +3759,8 @@ static SourceRange getRawCursorExtent(CXCursor C) {
if (C.kind == CXCursor_PreprocessingDirective)
return cxcursor::getCursorPreprocessingDirective(C);
- if (C.kind == CXCursor_MacroInstantiation)
- return cxcursor::getCursorMacroInstantiation(C)->getSourceRange();
+ if (C.kind == CXCursor_MacroExpansion)
+ return cxcursor::getCursorMacroExpansion(C)->getSourceRange();
if (C.kind == CXCursor_MacroDefinition)
return cxcursor::getCursorMacroDefinition(C)->getSourceRange();
@@ -3842,8 +3876,8 @@ CXCursor clang_getCursorReferenced(CXCursor C) {
return clang_getNullCursor();
}
- if (C.kind == CXCursor_MacroInstantiation) {
- if (MacroDefinition *Def = getCursorMacroInstantiation(C)->getDefinition())
+ if (C.kind == CXCursor_MacroExpansion) {
+ if (MacroDefinition *Def = getCursorMacroExpansion(C)->getDefinition())
return MakeMacroDefinitionCursor(Def, tu);
}
@@ -3911,7 +3945,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
WasReference = true;
}
- if (C.kind == CXCursor_MacroInstantiation)
+ if (C.kind == CXCursor_MacroExpansion)
return clang_getCursorReferenced(C);
if (!clang_isDeclaration(C.kind))
@@ -4107,8 +4141,17 @@ CXCursor clang_getCanonicalCursor(CXCursor C) {
if (!clang_isDeclaration(C.kind))
return C;
- if (Decl *D = getCursorDecl(C))
+ if (Decl *D = getCursorDecl(C)) {
+ if (ObjCCategoryImplDecl *CatImplD = dyn_cast<ObjCCategoryImplDecl>(D))
+ if (ObjCCategoryDecl *CatD = CatImplD->getCategoryDecl())
+ return MakeCXCursor(CatD, getCursorTU(C));
+
+ if (ObjCImplDecl *ImplD = dyn_cast<ObjCImplDecl>(D))
+ if (ObjCInterfaceDecl *IFD = ImplD->getClassInterface())
+ return MakeCXCursor(IFD, getCursorTU(C));
+
return MakeCXCursor(D->getCanonicalDecl(), getCursorTU(C));
+ }
return C;
}
@@ -4507,9 +4550,9 @@ AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) {
}
if (clang_isPreprocessing(cursor.kind)) {
- // For macro instantiations, just note where the beginning of the macro
- // instantiation occurs.
- if (cursor.kind == CXCursor_MacroInstantiation) {
+ // For macro expansions, just note where the beginning of the macro
+ // expansion occurs.
+ if (cursor.kind == CXCursor_MacroExpansion) {
Annotated[Loc.int_data] = cursor;
return CXChildVisit_Recurse;
}
@@ -4626,6 +4669,24 @@ AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) {
break;
}
+ // Avoid having the cursor of an expression "overwrite" the annotation of the
+ // variable declaration that it belongs to.
+ // This can happen for C++ constructor expressions whose range generally
+ // include the variable declaration, e.g.:
+ // MyCXXClass foo; // Make sure we don't annotate 'foo' as a CallExpr cursor.
+ if (clang_isExpression(cursorK)) {
+ Expr *E = getCursorExpr(cursor);
+ if (Decl *D = getCursorParentDecl(cursor)) {
+ const unsigned I = NextToken();
+ if (E->getLocStart().isValid() && D->getLocation().isValid() &&
+ E->getLocStart() == D->getLocation() &&
+ E->getLocStart() == GetTokenLoc(I)) {
+ Cursors[I] = updateC;
+ AdvanceToken();
+ }
+ }
+ }
+
// Visit children to get their cursor information.
const unsigned BeforeChildren = NextToken();
VisitChildren(cursor);
@@ -4797,6 +4858,7 @@ static void clang_annotateTokensImpl(void *UserData) {
llvm::StringSwitch<bool>(II->getName())
.Case("readonly", true)
.Case("assign", true)
+ .Case("unsafe_unretained", true)
.Case("readwrite", true)
.Case("retain", true)
.Case("copy", true)
@@ -4804,6 +4866,8 @@ static void clang_annotateTokensImpl(void *UserData) {
.Case("atomic", true)
.Case("getter", true)
.Case("setter", true)
+ .Case("strong", true)
+ .Case("weak", true)
.Default(false))
Tokens[I].int_data[0] = CXToken_Keyword;
}
@@ -5354,10 +5418,9 @@ CXTUResourceUsage clang_getCXTUResourceUsage(CXTranslationUnit TU) {
// How much memory is being used by the Preprocessor?
Preprocessor &pp = astUnit->getPreprocessor();
- const llvm::BumpPtrAllocator &ppAlloc = pp.getPreprocessorAllocator();
createCXTUResourceUsageEntry(*entries,
CXTUResourceUsage_Preprocessor,
- ppAlloc.getTotalMemory());
+ pp.getTotalMemory());
if (PreprocessingRecord *pRec = pp.getPreprocessingRecord()) {
createCXTUResourceUsageEntry(*entries,
diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp
index 0c8317e4461f..832e2f2f7147 100644
--- a/tools/libclang/CIndexCodeCompletion.cpp
+++ b/tools/libclang/CIndexCodeCompletion.cpp
@@ -235,6 +235,13 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
/// \brief Allocator used to store code completion results.
clang::CodeCompletionAllocator CodeCompletionAllocator;
+
+ /// \brief Context under which completion occurred.
+ enum clang::CodeCompletionContext::Kind ContextKind;
+
+ /// \brief A bitfield representing the acceptable completions for the
+ /// current context.
+ unsigned long long Contexts;
};
/// \brief Tracks the number of code-completion result objects that are
@@ -273,6 +280,177 @@ AllocatedCXCodeCompleteResults::~AllocatedCXCodeCompleteResults() {
} // end extern "C"
+static unsigned long long getContextsForContextKind(
+ enum CodeCompletionContext::Kind kind,
+ Sema &S) {
+ unsigned long long contexts = 0;
+ switch (kind) {
+ case CodeCompletionContext::CCC_OtherWithMacros: {
+ //We can allow macros here, but we don't know what else is permissible
+ //So we'll say the only thing permissible are macros
+ contexts = CXCompletionContext_MacroName;
+ break;
+ }
+ case CodeCompletionContext::CCC_TopLevel:
+ case CodeCompletionContext::CCC_ObjCIvarList:
+ case CodeCompletionContext::CCC_ClassStructUnion:
+ case CodeCompletionContext::CCC_Type: {
+ contexts = CXCompletionContext_AnyType |
+ CXCompletionContext_ObjCInterface;
+ if (S.getLangOptions().CPlusPlus) {
+ contexts |= CXCompletionContext_EnumTag |
+ CXCompletionContext_UnionTag |
+ CXCompletionContext_StructTag |
+ CXCompletionContext_ClassTag |
+ CXCompletionContext_NestedNameSpecifier;
+ }
+ break;
+ }
+ case CodeCompletionContext::CCC_Statement: {
+ contexts = CXCompletionContext_AnyType |
+ CXCompletionContext_ObjCInterface |
+ CXCompletionContext_AnyValue;
+ if (S.getLangOptions().CPlusPlus) {
+ contexts |= CXCompletionContext_EnumTag |
+ CXCompletionContext_UnionTag |
+ CXCompletionContext_StructTag |
+ CXCompletionContext_ClassTag |
+ CXCompletionContext_NestedNameSpecifier;
+ }
+ break;
+ }
+ case CodeCompletionContext::CCC_Expression: {
+ contexts = CXCompletionContext_AnyValue;
+ if (S.getLangOptions().CPlusPlus) {
+ contexts |= CXCompletionContext_AnyType |
+ CXCompletionContext_ObjCInterface |
+ CXCompletionContext_EnumTag |
+ CXCompletionContext_UnionTag |
+ CXCompletionContext_StructTag |
+ CXCompletionContext_ClassTag |
+ CXCompletionContext_NestedNameSpecifier;
+ }
+ break;
+ }
+ case CodeCompletionContext::CCC_ObjCMessageReceiver: {
+ contexts = CXCompletionContext_ObjCObjectValue |
+ CXCompletionContext_ObjCSelectorValue |
+ CXCompletionContext_ObjCInterface;
+ if (S.getLangOptions().CPlusPlus) {
+ contexts |= CXCompletionContext_CXXClassTypeValue |
+ CXCompletionContext_AnyType |
+ CXCompletionContext_EnumTag |
+ CXCompletionContext_UnionTag |
+ CXCompletionContext_StructTag |
+ CXCompletionContext_ClassTag |
+ CXCompletionContext_NestedNameSpecifier;
+ }
+ break;
+ }
+ case CodeCompletionContext::CCC_DotMemberAccess: {
+ contexts = CXCompletionContext_DotMemberAccess;
+ break;
+ }
+ case CodeCompletionContext::CCC_ArrowMemberAccess: {
+ contexts = CXCompletionContext_ArrowMemberAccess;
+ break;
+ }
+ case CodeCompletionContext::CCC_ObjCPropertyAccess: {
+ contexts = CXCompletionContext_ObjCPropertyAccess;
+ break;
+ }
+ case CodeCompletionContext::CCC_EnumTag: {
+ contexts = CXCompletionContext_EnumTag |
+ CXCompletionContext_NestedNameSpecifier;
+ break;
+ }
+ case CodeCompletionContext::CCC_UnionTag: {
+ contexts = CXCompletionContext_UnionTag |
+ CXCompletionContext_NestedNameSpecifier;
+ break;
+ }
+ case CodeCompletionContext::CCC_ClassOrStructTag: {
+ contexts = CXCompletionContext_StructTag |
+ CXCompletionContext_ClassTag |
+ CXCompletionContext_NestedNameSpecifier;
+ break;
+ }
+ case CodeCompletionContext::CCC_ObjCProtocolName: {
+ contexts = CXCompletionContext_ObjCProtocol;
+ break;
+ }
+ case CodeCompletionContext::CCC_Namespace: {
+ contexts = CXCompletionContext_Namespace;
+ break;
+ }
+ case CodeCompletionContext::CCC_PotentiallyQualifiedName: {
+ contexts = CXCompletionContext_NestedNameSpecifier;
+ break;
+ }
+ case CodeCompletionContext::CCC_MacroNameUse: {
+ contexts = CXCompletionContext_MacroName;
+ break;
+ }
+ case CodeCompletionContext::CCC_NaturalLanguage: {
+ contexts = CXCompletionContext_NaturalLanguage;
+ break;
+ }
+ case CodeCompletionContext::CCC_SelectorName: {
+ contexts = CXCompletionContext_ObjCSelectorName;
+ break;
+ }
+ case CodeCompletionContext::CCC_ParenthesizedExpression: {
+ contexts = CXCompletionContext_AnyType |
+ CXCompletionContext_ObjCInterface |
+ CXCompletionContext_AnyValue;
+ if (S.getLangOptions().CPlusPlus) {
+ contexts |= CXCompletionContext_EnumTag |
+ CXCompletionContext_UnionTag |
+ CXCompletionContext_StructTag |
+ CXCompletionContext_ClassTag |
+ CXCompletionContext_NestedNameSpecifier;
+ }
+ break;
+ }
+ case CodeCompletionContext::CCC_ObjCInstanceMessage: {
+ contexts = CXCompletionContext_ObjCInstanceMessage;
+ break;
+ }
+ case CodeCompletionContext::CCC_ObjCClassMessage: {
+ contexts = CXCompletionContext_ObjCClassMessage;
+ break;
+ }
+ case CodeCompletionContext::CCC_ObjCSuperclass: {
+ contexts = CXCompletionContext_ObjCInterface;
+ break;
+ }
+ case CodeCompletionContext::CCC_ObjCCategoryName: {
+ contexts = CXCompletionContext_ObjCCategory;
+ break;
+ }
+ case CodeCompletionContext::CCC_Other:
+ case CodeCompletionContext::CCC_ObjCInterface:
+ case CodeCompletionContext::CCC_ObjCImplementation:
+ case CodeCompletionContext::CCC_Name:
+ case CodeCompletionContext::CCC_MacroName:
+ case CodeCompletionContext::CCC_PreprocessorExpression:
+ case CodeCompletionContext::CCC_PreprocessorDirective:
+ case CodeCompletionContext::CCC_TypeQualifiers: {
+ //Only Clang results should be accepted, so we'll set all of the other
+ //context bits to 0 (i.e. the empty set)
+ contexts = CXCompletionContext_Unexposed;
+ break;
+ }
+ case CodeCompletionContext::CCC_Recovery: {
+ //We don't know what the current context is, so we'll return unknown
+ //This is the equivalent of setting all of the other context bits
+ contexts = CXCompletionContext_Unknown;
+ break;
+ }
+ }
+ return contexts;
+}
+
namespace {
class CaptureCompletionResults : public CodeCompleteConsumer {
AllocatedCXCodeCompleteResults &AllocatedResults;
@@ -298,6 +476,11 @@ namespace {
R.CompletionString = StoredCompletion;
StoredResults.push_back(R);
}
+
+ enum CodeCompletionContext::Kind kind = Context.getKind();
+
+ AllocatedResults.ContextKind = kind;
+ AllocatedResults.Contexts = getContextsForContextKind(kind, S);
}
virtual void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg,
@@ -538,6 +721,15 @@ clang_codeCompleteGetDiagnostic(CXCodeCompleteResults *ResultsIn,
return new CXStoredDiagnostic(Results->Diagnostics[Index], Results->LangOpts);
}
+unsigned long long
+clang_codeCompleteGetContexts(CXCodeCompleteResults *ResultsIn) {
+ AllocatedCXCodeCompleteResults *Results
+ = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn);
+ if (!Results)
+ return 0;
+
+ return Results->Contexts;
+}
} // end extern "C"
diff --git a/tools/libclang/CMakeLists.txt b/tools/libclang/CMakeLists.txt
index 7a6270d17647..f45389f0b9f4 100644
--- a/tools/libclang/CMakeLists.txt
+++ b/tools/libclang/CMakeLists.txt
@@ -1,4 +1,6 @@
set(LLVM_USED_LIBS
+ clangARCMigrate
+ clangRewrite
clangFrontend
clangDriver
clangSerialization
@@ -14,6 +16,7 @@ set( LLVM_LINK_COMPONENTS
)
set(SOURCES
+ ARCMigrate.cpp
CIndex.cpp
CIndexCXX.cpp
CIndexCodeCompletion.cpp
diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp
index b34370d2e652..b3c57dc9344f 100644
--- a/tools/libclang/CXCursor.cpp
+++ b/tools/libclang/CXCursor.cpp
@@ -92,6 +92,7 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent,
case Stmt::ObjCAtFinallyStmtClass:
case Stmt::ObjCAtThrowStmtClass:
case Stmt::ObjCAtSynchronizedStmtClass:
+ case Stmt::ObjCAutoreleasePoolStmtClass:
case Stmt::ObjCForCollectionStmtClass:
case Stmt::CXXCatchStmtClass:
case Stmt::CXXTryStmtClass:
@@ -99,6 +100,7 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent,
case Stmt::SEHTryStmtClass:
case Stmt::SEHExceptStmtClass:
case Stmt::SEHFinallyStmtClass:
+ case Stmt::MaterializeTemporaryExprClass:
K = CXCursor_UnexposedStmt;
break;
@@ -167,7 +169,9 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent,
case Stmt::ObjCEncodeExprClass:
case Stmt::ObjCSelectorExprClass:
case Stmt::ObjCProtocolExprClass:
- case Stmt::ObjCIsaExprClass:
+ case Stmt::ObjCIsaExprClass:
+ case Stmt::ObjCIndirectCopyRestoreExprClass:
+ case Stmt::ObjCBridgedCastExprClass:
case Stmt::ShuffleVectorExprClass:
case Stmt::BlockExprClass:
case Stmt::OpaqueValueExprClass:
@@ -179,6 +183,7 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent,
case Stmt::DeclRefExprClass:
case Stmt::BlockDeclRefExprClass:
+ case Stmt::SubstNonTypeTemplateParmExprClass:
case Stmt::SubstNonTypeTemplateParmPackExprClass:
// FIXME: UnresolvedLookupExpr?
// FIXME: DependentScopeDeclRefExpr?
@@ -374,15 +379,15 @@ MacroDefinition *cxcursor::getCursorMacroDefinition(CXCursor C) {
return static_cast<MacroDefinition *>(C.data[0]);
}
-CXCursor cxcursor::MakeMacroInstantiationCursor(MacroInstantiation *MI,
- CXTranslationUnit TU) {
- CXCursor C = { CXCursor_MacroInstantiation, { MI, 0, TU } };
+CXCursor cxcursor::MakeMacroExpansionCursor(MacroExpansion *MI,
+ CXTranslationUnit TU) {
+ CXCursor C = { CXCursor_MacroExpansion, { MI, 0, TU } };
return C;
}
-MacroInstantiation *cxcursor::getCursorMacroInstantiation(CXCursor C) {
- assert(C.kind == CXCursor_MacroInstantiation);
- return static_cast<MacroInstantiation *>(C.data[0]);
+MacroExpansion *cxcursor::getCursorMacroExpansion(CXCursor C) {
+ assert(C.kind == CXCursor_MacroExpansion);
+ return static_cast<MacroExpansion *>(C.data[0]);
}
CXCursor cxcursor::MakeInclusionDirectiveCursor(InclusionDirective *ID,
@@ -480,6 +485,10 @@ Attr *cxcursor::getCursorAttr(CXCursor Cursor) {
return (Attr *)Cursor.data[1];
}
+Decl *cxcursor::getCursorParentDecl(CXCursor Cursor) {
+ return (Decl *)Cursor.data[0];
+}
+
ASTContext &cxcursor::getCursorContext(CXCursor Cursor) {
return getCursorASTUnit(Cursor)->getASTContext();
}
diff --git a/tools/libclang/CXCursor.h b/tools/libclang/CXCursor.h
index 11f2500fb144..68d09e76c1c0 100644
--- a/tools/libclang/CXCursor.h
+++ b/tools/libclang/CXCursor.h
@@ -31,7 +31,7 @@ class FieldDecl;
class InclusionDirective;
class LabelStmt;
class MacroDefinition;
-class MacroInstantiation;
+class MacroExpansion;
class NamedDecl;
class ObjCInterfaceDecl;
class ObjCProtocolDecl;
@@ -134,13 +134,13 @@ CXCursor MakeMacroDefinitionCursor(MacroDefinition *, CXTranslationUnit TU);
/// source range.
MacroDefinition *getCursorMacroDefinition(CXCursor C);
-/// \brief Create a macro instantiation cursor.
-CXCursor MakeMacroInstantiationCursor(MacroInstantiation *,
- CXTranslationUnit TU);
+/// \brief Create a macro expansion cursor.
+CXCursor MakeMacroExpansionCursor(MacroExpansion *,
+ CXTranslationUnit TU);
-/// \brief Unpack a given macro instantiation cursor to retrieve its
+/// \brief Unpack a given macro expansion cursor to retrieve its
/// source range.
-MacroInstantiation *getCursorMacroInstantiation(CXCursor C);
+MacroExpansion *getCursorMacroExpansion(CXCursor C);
/// \brief Create an inclusion directive cursor.
CXCursor MakeInclusionDirectiveCursor(InclusionDirective *,
@@ -184,6 +184,7 @@ Decl *getCursorDecl(CXCursor Cursor);
Expr *getCursorExpr(CXCursor Cursor);
Stmt *getCursorStmt(CXCursor Cursor);
Attr *getCursorAttr(CXCursor Cursor);
+Decl *getCursorParentDecl(CXCursor Cursor);
ASTContext &getCursorContext(CXCursor Cursor);
ASTUnit *getCursorASTUnit(CXCursor Cursor);
diff --git a/tools/libclang/CXType.cpp b/tools/libclang/CXType.cpp
index 5af955357bb2..45c73468d971 100644
--- a/tools/libclang/CXType.cpp
+++ b/tools/libclang/CXType.cpp
@@ -366,7 +366,11 @@ unsigned clang_isPODType(CXType X) {
QualType T = GetQualType(X);
if (!T.getTypePtrOrNull())
return 0;
- return T->isPODType() ? 1 : 0;
+
+ CXTranslationUnit TU = GetTU(X);
+ ASTUnit *AU = static_cast<ASTUnit*>(TU->TUData);
+
+ return T.isPODType(AU->getASTContext()) ? 1 : 0;
}
CXString clang_getDeclObjCTypeEncoding(CXCursor C) {
diff --git a/tools/libclang/Makefile b/tools/libclang/Makefile
index e684652aa4ca..375f7f20fe00 100644
--- a/tools/libclang/Makefile
+++ b/tools/libclang/Makefile
@@ -16,8 +16,9 @@ LINK_LIBS_IN_SHARED = 1
SHARED_LIBRARY = 1
LINK_COMPONENTS := support mc
-USEDLIBS = clangFrontend.a clangDriver.a clangSerialization.a clangParse.a \
- clangSema.a clangAnalysis.a clangAST.a clangLex.a clangBasic.a
+USEDLIBS = clangARCMigrate.a clangRewrite.a clangFrontend.a clangDriver.a \
+ clangSerialization.a \
+ clangParse.a clangSema.a clangAnalysis.a clangAST.a clangLex.a clangBasic.a
include $(CLANG_LEVEL)/Makefile
diff --git a/tools/libclang/libclang.darwin.exports b/tools/libclang/libclang.darwin.exports
index 85dfcb68685c..bfc5be9c078b 100644
--- a/tools/libclang/libclang.darwin.exports
+++ b/tools/libclang/libclang.darwin.exports
@@ -6,6 +6,7 @@ _clang_annotateTokens
_clang_codeCompleteAt
_clang_codeCompleteGetDiagnostic
_clang_codeCompleteGetNumDiagnostics
+_clang_codeCompleteGetContexts
_clang_constructUSR_ObjCCategory
_clang_constructUSR_ObjCClass
_clang_constructUSR_ObjCIvar
@@ -112,6 +113,7 @@ _clang_getTranslationUnitSpelling
_clang_getTypeDeclaration
_clang_getTypeKindSpelling
_clang_hashCursor
+_clang_isAttribute
_clang_isConstQualifiedType
_clang_isCursorDefinition
_clang_isDeclaration
@@ -135,3 +137,7 @@ _clang_toggleCrashRecovery
_clang_tokenize
_clang_visitChildren
_clang_visitChildrenWithBlock
+_clang_getRemappings
+_clang_remap_getNumFiles
+_clang_remap_getFilenames
+_clang_remap_dispose
diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports
index 403cd67538c5..47b703011c76 100644
--- a/tools/libclang/libclang.exports
+++ b/tools/libclang/libclang.exports
@@ -6,6 +6,7 @@ clang_annotateTokens
clang_codeCompleteAt
clang_codeCompleteGetDiagnostic
clang_codeCompleteGetNumDiagnostics
+clang_codeCompleteGetContexts
clang_constructUSR_ObjCCategory
clang_constructUSR_ObjCClass
clang_constructUSR_ObjCIvar
@@ -112,6 +113,7 @@ clang_getTranslationUnitSpelling
clang_getTypeDeclaration
clang_getTypeKindSpelling
clang_hashCursor
+clang_isAttribute
clang_isConstQualifiedType
clang_isCursorDefinition
clang_isDeclaration
@@ -135,3 +137,7 @@ clang_toggleCrashRecovery
clang_tokenize
clang_visitChildren
clang_visitChildrenWithBlock
+clang_getRemappings
+clang_remap_getNumFiles
+clang_remap_getFilenames
+clang_remap_dispose
diff --git a/tools/scan-build/ccc-analyzer b/tools/scan-build/ccc-analyzer
index 7793a8db49b1..5697b214a2d7 100755
--- a/tools/scan-build/ccc-analyzer
+++ b/tools/scan-build/ccc-analyzer
@@ -365,11 +365,9 @@ my %LangMap = (
'cp' => 'c++',
'cpp' => 'c++',
'cc' => 'c++',
- 'ii' => 'c++',
'i' => 'c-cpp-output',
'm' => 'objective-c',
- 'mi' => 'objective-c-cpp-output',
- 'mm' => 'objective-c++'
+ 'mi' => 'objective-c-cpp-output'
);
my %UniqueOptions = (
@@ -382,11 +380,14 @@ my %UniqueOptions = (
my %LangsAccepted = (
"objective-c" => 1,
- "c" => 1,
- "c++" => 1,
- "objective-c++" => 1
+ "c" => 1
);
+if (defined $ENV{'CCC_ANALYZER_CPLUSPLUS'}) {
+ $LangsAccepted{"c++"} = 1;
+ $LangsAccepted{"objective-c++"} = 1;
+}
+
##----------------------------------------------------------------------------##
# Main Logic.
##----------------------------------------------------------------------------##
@@ -620,9 +621,9 @@ if ($Action eq 'compile' or $Action eq 'link') {
push @AnalyzeArgs, "-analyzer-constraints=$ConstraintsModel";
}
- if (defined $Analyses) {
- push @AnalyzeArgs, split '\s+', $Analyses;
- }
+# if (defined $Analyses) {
+# push @AnalyzeArgs, split '\s+', $Analyses;
+# }
if (defined $OutputFormat) {
push @AnalyzeArgs, "-analyzer-output=" . $OutputFormat;
diff --git a/unittests/Basic/FileManagerTest.cpp b/unittests/Basic/FileManagerTest.cpp
index 80727790d038..a725a437f6b7 100644
--- a/unittests/Basic/FileManagerTest.cpp
+++ b/unittests/Basic/FileManagerTest.cpp
@@ -30,7 +30,7 @@ private:
void InjectFileOrDirectory(const char *Path, ino_t INode, bool IsFile) {
struct stat statBuf = {};
statBuf.st_dev = 1;
-#ifndef LLVM_ON_WIN32 // struct stat has no st_ino field on Windows.
+#ifndef _WIN32 // struct stat has no st_ino field on Windows.
statBuf.st_ino = INode;
#endif
statBuf.st_mode = IsFile ? (0777 | S_IFREG) // a regular file
@@ -187,7 +187,7 @@ TEST_F(FileManagerTest, getFileReturnsNULLForNonexistentFile) {
// The following tests apply to Unix-like system only.
-#ifndef LLVM_ON_WIN32
+#ifndef _WIN32
// getFile() returns the same FileEntry for real files that are aliases.
TEST_F(FileManagerTest, getFileReturnsSameFileEntryForAliasedRealFiles) {
@@ -217,6 +217,6 @@ TEST_F(FileManagerTest, getFileReturnsSameFileEntryForAliasedVirtualFiles) {
EXPECT_EQ(manager.getFile("abc/foo.cpp"), manager.getFile("abc/bar.cpp"));
}
-#endif // !LLVM_ON_WIN32
+#endif // !_WIN32
} // anonymous namespace
diff --git a/unittests/Frontend/Makefile b/unittests/Frontend/Makefile
index 4d9937f517cf..7ec2b894a04b 100644
--- a/unittests/Frontend/Makefile
+++ b/unittests/Frontend/Makefile
@@ -13,7 +13,7 @@ LINK_COMPONENTS := support mc
USEDLIBS = clangFrontendTool.a clangFrontend.a clangDriver.a \
clangSerialization.a clangCodeGen.a clangParse.a clangSema.a \
clangStaticAnalyzerCheckers.a clangStaticAnalyzerCore.a \
- clangAnalysis.a clangIndex.a clangRewrite.a \
- clangAST.a clangLex.a clangBasic.a
+ clangIndex.a clangARCMigrate.a clangRewrite.a \
+ clangAnalysis.a clangAST.a clangLex.a clangBasic.a
include $(CLANG_LEVEL)/unittests/Makefile
diff --git a/www/compatibility.html b/www/compatibility.html
index b68a7663d4fb..783758f3ac80 100644
--- a/www/compatibility.html
+++ b/www/compatibility.html
@@ -459,7 +459,7 @@ int main() {
<p>Clang complains:
-<pre> <b>my_file.cpp:2:10: <span class="error">error:</span> call to function 'Multiply' that is neither visible in the template definition nor found by argument dependent lookup</b>
+<pre> <b>my_file.cpp:2:10: <span class="error">error:</span> call to function 'Multiply' that is neither visible in the template definition nor found by argument-dependent lookup</b>
return Multiply(x, x);
<span class="caret"> ^</span>
<b>my_file.cpp:10:3: <span class="note">note:</span> in instantiation of function template specialization 'Squared&lt;int&gt;' requested here</b>
@@ -520,7 +520,7 @@ void Use() {
<p>Again, Clang complains:</p>
-<pre> <b>my_file2.cpp:5:13: <span class="error">error:</span> call to function 'operator&lt;&lt;' that is neither visible in the template definition nor found by argument dependent lookup</b>
+<pre> <b>my_file2.cpp:5:13: <span class="error">error:</span> call to function 'operator&lt;&lt;' that is neither visible in the template definition nor found by argument-dependent lookup</b>
std::cout &lt;&lt; value &lt;&lt; "\n";
<span class="caret"> ^</span>
<b>my_file2.cpp:17:3: <span class="error">note:</span> in instantiation of function template specialization 'Dump&lt;ns::Data&gt;' requested here</b>